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:
Diffstat (limited to 'source')
-rw-r--r--source/blender/CMakeLists.txt4
-rw-r--r--source/blender/alembic/ABC_alembic.h55
-rw-r--r--source/blender/alembic/CMakeLists.txt6
-rw-r--r--source/blender/alembic/intern/abc_archive.cc63
-rw-r--r--source/blender/alembic/intern/abc_archive.h9
-rw-r--r--source/blender/alembic/intern/abc_camera.cc38
-rw-r--r--source/blender/alembic/intern/abc_camera.h7
-rw-r--r--source/blender/alembic/intern/abc_curves.cc88
-rw-r--r--source/blender/alembic/intern/abc_curves.h14
-rw-r--r--source/blender/alembic/intern/abc_customdata.cc212
-rw-r--r--source/blender/alembic/intern/abc_customdata.h8
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc331
-rw-r--r--source/blender/alembic/intern/abc_exporter.h28
-rw-r--r--source/blender/alembic/intern/abc_hair.cc50
-rw-r--r--source/blender/alembic/intern/abc_hair.h2
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc451
-rw-r--r--source/blender/alembic/intern/abc_mesh.h38
-rw-r--r--source/blender/alembic/intern/abc_nurbs.cc7
-rw-r--r--source/blender/alembic/intern/abc_nurbs.h2
-rw-r--r--source/blender/alembic/intern/abc_object.cc131
-rw-r--r--source/blender/alembic/intern/abc_object.h58
-rw-r--r--source/blender/alembic/intern/abc_points.cc35
-rw-r--r--source/blender/alembic/intern/abc_points.h15
-rw-r--r--source/blender/alembic/intern/abc_transform.cc58
-rw-r--r--source/blender/alembic/intern/abc_transform.h11
-rw-r--r--source/blender/alembic/intern/abc_util.cc371
-rw-r--r--source/blender/alembic/intern/abc_util.h124
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc652
-rw-r--r--source/blender/blenfont/BLF_api.h2
-rw-r--r--source/blender/blenfont/intern/blf.c7
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c1
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c4
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h19
-rw-r--r--source/blender/blenkernel/BKE_action.h8
-rw-r--r--source/blender/blenkernel/BKE_animsys.h14
-rw-r--r--source/blender/blenkernel/BKE_appdir.h4
-rw-r--r--source/blender/blenkernel/BKE_armature.h9
-rw-r--r--source/blender/blenkernel/BKE_blender.h13
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h4
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h20
-rw-r--r--source/blender/blenkernel/BKE_boids.h2
-rw-r--r--source/blender/blenkernel/BKE_brush.h15
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h16
-rw-r--r--source/blender/blenkernel/BKE_cachefile.h6
-rw-r--r--source/blender/blenkernel/BKE_camera.h3
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h1
-rw-r--r--source/blender/blenkernel/BKE_cloth.h6
-rw-r--r--source/blender/blenkernel/BKE_colortools.h4
-rw-r--r--source/blender/blenkernel/BKE_constraint.h1
-rw-r--r--source/blender/blenkernel/BKE_curve.h26
-rw-r--r--source/blender/blenkernel/BKE_deform.h13
-rw-r--r--source/blender/blenkernel/BKE_effect.h16
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h14
-rw-r--r--source/blender/blenkernel/BKE_font.h4
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h2
-rw-r--r--source/blender/blenkernel/BKE_global.h10
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h5
-rw-r--r--source/blender/blenkernel/BKE_group.h3
-rw-r--r--source/blender/blenkernel/BKE_icons.h6
-rw-r--r--source/blender/blenkernel/BKE_idprop.h16
-rw-r--r--source/blender/blenkernel/BKE_image.h4
-rw-r--r--source/blender/blenkernel/BKE_key.h3
-rw-r--r--source/blender/blenkernel/BKE_lamp.h3
-rw-r--r--source/blender/blenkernel/BKE_lattice.h3
-rw-r--r--source/blender/blenkernel/BKE_library.h85
-rw-r--r--source/blender/blenkernel/BKE_library_query.h38
-rw-r--r--source/blender/blenkernel/BKE_library_remap.h6
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h17
-rw-r--r--source/blender/blenkernel/BKE_main.h23
-rw-r--r--source/blender/blenkernel/BKE_mask.h16
-rw-r--r--source/blender/blenkernel/BKE_material.h3
-rw-r--r--source/blender/blenkernel/BKE_mball.h5
-rw-r--r--source/blender/blenkernel/BKE_mesh.h15
-rw-r--r--source/blender/blenkernel/BKE_modifier.h7
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h3
-rw-r--r--source/blender/blenkernel/BKE_node.h14
-rw-r--r--source/blender/blenkernel/BKE_object.h28
-rw-r--r--source/blender/blenkernel/BKE_paint.h46
-rw-r--r--source/blender/blenkernel/BKE_particle.h16
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h23
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h2
-rw-r--r--source/blender/blenkernel/BKE_property.h4
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h9
-rw-r--r--source/blender/blenkernel/BKE_sca.h20
-rw-r--r--source/blender/blenkernel/BKE_scene.h6
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h7
-rw-r--r--source/blender/blenkernel/BKE_sound.h4
-rw-r--r--source/blender/blenkernel/BKE_speaker.h3
-rw-r--r--source/blender/blenkernel/BKE_text.h3
-rw-r--r--source/blender/blenkernel/BKE_texture.h18
-rw-r--r--source/blender/blenkernel/BKE_tracking.h2
-rw-r--r--source/blender/blenkernel/BKE_world.h3
-rw-r--r--source/blender/blenkernel/CMakeLists.txt10
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c177
-rw-r--r--source/blender/blenkernel/intern/action.c103
-rw-r--r--source/blender/blenkernel/intern/anim.c10
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c104
-rw-r--r--source/blender/blenkernel/intern/appdir.c195
-rw-r--r--source/blender/blenkernel/intern/armature.c100
-rw-r--r--source/blender/blenkernel/intern/armature_update.c19
-rw-r--r--source/blender/blenkernel/intern/blender.c123
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c6
-rw-r--r--source/blender/blenkernel/intern/blendfile.c101
-rw-r--r--source/blender/blenkernel/intern/boids.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c2
-rw-r--r--source/blender/blenkernel/intern/brush.c77
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c427
-rw-r--r--source/blender/blenkernel/intern/cachefile.c41
-rw-r--r--source/blender/blenkernel/intern/camera.c29
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c337
-rw-r--r--source/blender/blenkernel/intern/cloth.c38
-rw-r--r--source/blender/blenkernel/intern/collision.c6
-rw-r--r--source/blender/blenkernel/intern/colortools.c8
-rw-r--r--source/blender/blenkernel/intern/constraint.c43
-rw-r--r--source/blender/blenkernel/intern/curve.c154
-rw-r--r--source/blender/blenkernel/intern/customdata.c76
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c34
-rw-r--r--source/blender/blenkernel/intern/deform.c202
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c31
-rw-r--r--source/blender/blenkernel/intern/displist.c13
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c571
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c179
-rw-r--r--source/blender/blenkernel/intern/effect.c55
-rw-r--r--source/blender/blenkernel/intern/fcurve.c153
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c2
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c14
-rw-r--r--source/blender/blenkernel/intern/font.c29
-rw-r--r--source/blender/blenkernel/intern/freestyle.c19
-rw-r--r--source/blender/blenkernel/intern/gpencil.c97
-rw-r--r--source/blender/blenkernel/intern/group.c35
-rw-r--r--source/blender/blenkernel/intern/icons.c8
-rw-r--r--source/blender/blenkernel/intern/idprop.c223
-rw-r--r--source/blender/blenkernel/intern/image.c154
-rw-r--r--source/blender/blenkernel/intern/image_gen.c2
-rw-r--r--source/blender/blenkernel/intern/ipo.c1
-rw-r--r--source/blender/blenkernel/intern/key.c57
-rw-r--r--source/blender/blenkernel/intern/lamp.c64
-rw-r--r--source/blender/blenkernel/intern/lattice.c47
-rw-r--r--source/blender/blenkernel/intern/library.c1025
-rw-r--r--source/blender/blenkernel/intern/library_query.c483
-rw-r--r--source/blender/blenkernel/intern/library_remap.c267
-rw-r--r--source/blender/blenkernel/intern/linestyle.c128
-rw-r--r--source/blender/blenkernel/intern/mask.c132
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c110
-rw-r--r--source/blender/blenkernel/intern/material.c76
-rw-r--r--source/blender/blenkernel/intern/mball.c59
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c17
-rw-r--r--source/blender/blenkernel/intern/mesh.c446
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c522
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c17
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c4
-rw-r--r--source/blender/blenkernel/intern/modifier.c32
-rw-r--r--source/blender/blenkernel/intern/movieclip.c38
-rw-r--r--source/blender/blenkernel/intern/nla.c2
-rw-r--r--source/blender/blenkernel/intern/node.c356
-rw-r--r--source/blender/blenkernel/intern/object.c301
-rw-r--r--source/blender/blenkernel/intern/object_deform.c5
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c51
-rw-r--r--source/blender/blenkernel/intern/object_update.c19
-rw-r--r--source/blender/blenkernel/intern/ocean.c2
-rw-r--r--source/blender/blenkernel/intern/packedFile.c10
-rw-r--r--source/blender/blenkernel/intern/paint.c102
-rw-r--r--source/blender/blenkernel/intern/particle.c129
-rw-r--r--source/blender/blenkernel/intern/particle_child.c8
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c71
-rw-r--r--source/blender/blenkernel/intern/particle_system.c189
-rw-r--r--source/blender/blenkernel/intern/pbvh.c364
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c127
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h20
-rw-r--r--source/blender/blenkernel/intern/pointcache.c19
-rw-r--r--source/blender/blenkernel/intern/property.c4
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c119
-rw-r--r--source/blender/blenkernel/intern/sca.c98
-rw-r--r--source/blender/blenkernel/intern/scene.c475
-rw-r--r--source/blender/blenkernel/intern/screen.c1
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c149
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c17
-rw-r--r--source/blender/blenkernel/intern/sequencer.c160
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c12
-rw-r--r--source/blender/blenkernel/intern/smoke.c13
-rw-r--r--source/blender/blenkernel/intern/softbody.c16
-rw-r--r--source/blender/blenkernel/intern/sound.c64
-rw-r--r--source/blender/blenkernel/intern/speaker.c28
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c130
-rw-r--r--source/blender/blenkernel/intern/text.c96
-rw-r--r--source/blender/blenkernel/intern/texture.c151
-rw-r--r--source/blender/blenkernel/intern/tracking.c97
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c124
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c19
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c232
-rw-r--r--source/blender/blenkernel/intern/unit.c11
-rw-r--r--source/blender/blenkernel/intern/world.c54
-rw-r--r--source/blender/blenkernel/intern/writeavi.c14
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c56
-rw-r--r--source/blender/blenkernel/intern/writeframeserver.c4
-rw-r--r--source/blender/blenkernel/tracking_private.h12
-rw-r--r--source/blender/blenlib/BLI_alloca.h4
-rw-r--r--source/blender/blenlib/BLI_array.h9
-rw-r--r--source/blender/blenlib/BLI_compiler_attrs.h8
-rw-r--r--source/blender/blenlib/BLI_compiler_compat.h12
-rw-r--r--source/blender/blenlib/BLI_dial.h4
-rw-r--r--source/blender/blenlib/BLI_dynlib.h2
-rw-r--r--source/blender/blenlib/BLI_dynstr.h6
-rw-r--r--source/blender/blenlib/BLI_fileops.h4
-rw-r--r--source/blender/blenlib/BLI_fileops_types.h6
-rw-r--r--source/blender/blenlib/BLI_fnmatch.h6
-rw-r--r--source/blender/blenlib/BLI_ghash.h25
-rw-r--r--source/blender/blenlib/BLI_hash.h66
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h20
-rw-r--r--source/blender/blenlib/BLI_kdtree.h4
-rw-r--r--source/blender/blenlib/BLI_listbase.h6
-rw-r--r--source/blender/blenlib/BLI_math_base.h89
-rw-r--r--source/blender/blenlib/BLI_math_geom.h76
-rw-r--r--source/blender/blenlib/BLI_math_inline.h7
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h1
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h11
-rw-r--r--source/blender/blenlib/BLI_math_vector.h7
-rw-r--r--source/blender/blenlib/BLI_path_util.h34
-rw-r--r--source/blender/blenlib/BLI_polyfill2d_beautify.h8
-rw-r--r--source/blender/blenlib/BLI_rect.h5
-rw-r--r--source/blender/blenlib/BLI_stack.h8
-rw-r--r--source/blender/blenlib/BLI_strict_flags.h2
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h4
-rw-r--r--source/blender/blenlib/BLI_string_utils.h82
-rw-r--r--source/blender/blenlib/BLI_sys_types.h9
-rw-r--r--source/blender/blenlib/BLI_task.h17
-rw-r--r--source/blender/blenlib/BLI_utildefines.h25
-rw-r--r--source/blender/blenlib/BLI_utildefines_iter.h52
-rw-r--r--source/blender/blenlib/BLI_utildefines_stack.h (renamed from source/blender/blenlib/BLI_stackdefines.h)8
-rw-r--r--source/blender/blenlib/BLI_utildefines_variadic.h50
-rw-r--r--source/blender/blenlib/BLI_vfontdata.h2
-rw-r--r--source/blender/blenlib/BLI_winstuff.h29
-rw-r--r--source/blender/blenlib/CMakeLists.txt7
-rw-r--r--source/blender/blenlib/PIL_time_utildefines.h5
-rw-r--r--source/blender/blenlib/intern/BLI_dial.c4
-rw-r--r--source/blender/blenlib/intern/BLI_dynstr.c70
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c51
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c624
-rw-r--r--source/blender/blenlib/intern/BLI_kdtree.c120
-rw-r--r--source/blender/blenlib/intern/array_store.c76
-rw-r--r--source/blender/blenlib/intern/bitmap_draw_2d.c43
-rw-r--r--source/blender/blenlib/intern/dynlib.c4
-rw-r--r--source/blender/blenlib/intern/fileops.c5
-rw-r--r--source/blender/blenlib/intern/freetypefont.c30
-rw-r--r--source/blender/blenlib/intern/hash_mm2a.c6
-rw-r--r--source/blender/blenlib/intern/listbase.c36
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c81
-rw-r--r--source/blender/blenlib/intern/math_color_blend_inline.c2
-rw-r--r--source/blender/blenlib/intern/math_geom.c575
-rw-r--r--source/blender/blenlib/intern/math_matrix.c73
-rw-r--r--source/blender/blenlib/intern/math_rotation.c62
-rw-r--r--source/blender/blenlib/intern/math_vector.c120
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c13
-rw-r--r--source/blender/blenlib/intern/noise.c10
-rw-r--r--source/blender/blenlib/intern/path_util.c352
-rw-r--r--source/blender/blenlib/intern/polyfill2d.c123
-rw-r--r--source/blender/blenlib/intern/polyfill2d_beautify.c56
-rw-r--r--source/blender/blenlib/intern/rct.c74
-rw-r--r--source/blender/blenlib/intern/storage.c38
-rw-r--r--source/blender/blenlib/intern/string.c4
-rw-r--r--source/blender/blenlib/intern/string_utf8.c163
-rw-r--r--source/blender/blenlib/intern/string_utils.c473
-rw-r--r--source/blender/blenlib/intern/task.c469
-rw-r--r--source/blender/blenlib/intern/threads.c44
-rw-r--r--source/blender/blenlib/intern/timecode.c10
-rw-r--r--source/blender/blenlib/intern/winstuff.c2
-rw-r--r--source/blender/blenloader/BLO_readfile.h20
-rw-r--r--source/blender/blenloader/CMakeLists.txt6
-rw-r--r--source/blender/blenloader/intern/readblenentry.c15
-rw-r--r--source/blender/blenloader/intern/readfile.c1246
-rw-r--r--source/blender/blenloader/intern/readfile.h4
-rw-r--r--source/blender/blenloader/intern/versioning_260.c4
-rw-r--r--source/blender/blenloader/intern/versioning_270.c262
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c43
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c13
-rw-r--r--source/blender/blenloader/intern/writefile.c2298
-rw-r--r--source/blender/blentranslation/CMakeLists.txt4
-rw-r--r--source/blender/blentranslation/msgfmt/CMakeLists.txt (renamed from source/blender/quicktime/CMakeLists.txt)46
-rw-r--r--source/blender/blentranslation/msgfmt/msgfmt.c467
-rw-r--r--source/blender/bmesh/CMakeLists.txt2
-rw-r--r--source/blender/bmesh/bmesh.h5
-rw-r--r--source/blender/bmesh/bmesh_class.h4
-rw-r--r--source/blender/bmesh/bmesh_tools.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_callback_generic.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c38
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h7
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c158
-rw-r--r--source/blender/bmesh/intern/bmesh_core.h52
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c29
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c68
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c142
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c163
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c204
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_validate.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c43
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h7
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c9
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c18
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h15
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c162
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c172
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h7
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c90
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.h5
-rw-r--r--source/blender/bmesh/operators/bmo_bevel.c2
-rw-r--r--source/blender/bmesh/operators/bmo_bisect_plane.c9
-rw-r--r--source/blender/bmesh/operators/bmo_connect.c4
-rw-r--r--source/blender/bmesh/operators/bmo_connect_nonplanar.c4
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c8
-rw-r--r--source/blender/bmesh/operators/bmo_create.c24
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c2
-rw-r--r--source/blender/bmesh/operators/bmo_dupe.c6
-rw-r--r--source/blender/bmesh/operators/bmo_fill_attribute.c4
-rw-r--r--source/blender/bmesh/operators/bmo_fill_grid.c20
-rw-r--r--source/blender/bmesh/operators/bmo_fill_holes.c2
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c16
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c12
-rw-r--r--source/blender/bmesh/operators/bmo_offset_edgeloops.c6
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c100
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c122
-rw-r--r--source/blender/bmesh/operators/bmo_smooth_laplacian.c6
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c28
-rw-r--r--source/blender/bmesh/operators/bmo_triangulate.c10
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c13
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c432
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c57
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.h2
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c10
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c28
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.c40
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c66
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.h2
-rw-r--r--source/blender/bmesh/tools/bmesh_path.c47
-rw-r--r--source/blender/bmesh/tools/bmesh_path.h4
-rw-r--r--source/blender/bmesh/tools/bmesh_path_region.c30
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c98
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.h2
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.c133
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.h32
-rw-r--r--source/blender/collada/AnimationExporter.cpp26
-rw-r--r--source/blender/collada/AnimationImporter.cpp4
-rw-r--r--source/blender/collada/ArmatureExporter.cpp94
-rw-r--r--source/blender/collada/ArmatureExporter.h2
-rw-r--r--source/blender/collada/ArmatureImporter.cpp66
-rw-r--r--source/blender/collada/ControllerExporter.cpp125
-rw-r--r--source/blender/collada/ControllerExporter.h2
-rw-r--r--source/blender/collada/DocumentExporter.cpp17
-rw-r--r--source/blender/collada/DocumentImporter.cpp14
-rw-r--r--source/blender/collada/EffectExporter.cpp134
-rw-r--r--source/blender/collada/EffectExporter.h1
-rw-r--r--source/blender/collada/ErrorHandler.cpp9
-rw-r--r--source/blender/collada/ExportSettings.h7
-rw-r--r--source/blender/collada/GeometryExporter.cpp311
-rw-r--r--source/blender/collada/GeometryExporter.h34
-rw-r--r--source/blender/collada/ImageExporter.cpp28
-rw-r--r--source/blender/collada/ImportSettings.h1
-rw-r--r--source/blender/collada/InstanceWriter.cpp63
-rw-r--r--source/blender/collada/InstanceWriter.h3
-rw-r--r--source/blender/collada/MaterialExporter.cpp35
-rw-r--r--source/blender/collada/MeshImporter.cpp7
-rw-r--r--source/blender/collada/SceneExporter.cpp5
-rw-r--r--source/blender/collada/SkinInfo.cpp3
-rw-r--r--source/blender/collada/TransformReader.cpp23
-rw-r--r--source/blender/collada/TransformReader.h5
-rw-r--r--source/blender/collada/TransformWriter.cpp7
-rw-r--r--source/blender/collada/TransformWriter.h3
-rw-r--r--source/blender/collada/collada.cpp17
-rw-r--r--source/blender/collada/collada.h17
-rw-r--r--source/blender/collada/collada_internal.cpp34
-rw-r--r--source/blender/collada/collada_internal.h8
-rw-r--r--source/blender/collada/collada_utils.cpp380
-rw-r--r--source/blender/collada/collada_utils.h25
-rw-r--r--source/blender/compositor/CMakeLists.txt4
-rw-r--r--source/blender/compositor/COM_compositor.h13
-rw-r--r--source/blender/compositor/intern/COM_Debug.cpp4
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cpp105
-rw-r--r--source/blender/compositor/intern/COM_compositor.cpp16
-rw-r--r--source/blender/compositor/nodes/COM_BrightnessNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_CompositorNode.cpp1
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp1
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp17
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cpp45
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.cpp198
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.h20
-rw-r--r--source/blender/compositor/nodes/COM_ScaleNode.cpp19
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.cpp14
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.h3
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.cpp19
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.h11
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cpp5
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp20
-rw-r--r--source/blender/compositor/operations/COM_GlareStreaksOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp77
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cpp188
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.h122
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.cpp78
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cpp29
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp6
-rw-r--r--source/blender/datatoc/CMakeLists.txt5
-rw-r--r--source/blender/datatoc/datatoc.c5
-rw-r--r--source/blender/depsgraph/CMakeLists.txt2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h3
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h3
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc101
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc42
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc460
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h28
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc123
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc43
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc1110
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h59
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc11
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc175
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc41
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc4
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc121
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc138
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h23
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc74
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc8
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc8
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc61
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc19
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h158
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc150
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_debug.cc6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc71
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.cc108
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.h53
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.cc59
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.h10
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.cc20
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.h13
-rw-r--r--source/blender/depsgraph/util/deg_util_foreach.h25
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c9
-rw-r--r--source/blender/editors/animation/anim_deps.c26
-rw-r--r--source/blender/editors/animation/anim_draw.c94
-rw-r--r--source/blender/editors/animation/anim_filter.c4
-rw-r--r--source/blender/editors/animation/anim_markers.c11
-rw-r--r--source/blender/editors/animation/anim_ops.c35
-rw-r--r--source/blender/editors/animation/drivers.c6
-rw-r--r--source/blender/editors/animation/keyframes_edit.c2
-rw-r--r--source/blender/editors/animation/keyframes_general.c4
-rw-r--r--source/blender/editors/animation/keyframing.c51
-rw-r--r--source/blender/editors/animation/keyingsets.c2
-rw-r--r--source/blender/editors/armature/armature_add.c11
-rw-r--r--source/blender/editors/armature/armature_edit.c30
-rw-r--r--source/blender/editors/armature/armature_intern.h6
-rw-r--r--source/blender/editors/armature/armature_naming.c69
-rw-r--r--source/blender/editors/armature/armature_relations.c4
-rw-r--r--source/blender/editors/armature/armature_select.c145
-rw-r--r--source/blender/editors/armature/armature_skinning.c3
-rw-r--r--source/blender/editors/armature/armature_utils.c3
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c12
-rw-r--r--source/blender/editors/armature/pose_edit.c16
-rw-r--r--source/blender/editors/armature/pose_lib.c3
-rw-r--r--source/blender/editors/armature/pose_select.c14
-rw-r--r--source/blender/editors/armature/pose_slide.c337
-rw-r--r--source/blender/editors/armature/pose_transform.c3
-rw-r--r--source/blender/editors/armature/reeb.c2
-rw-r--r--source/blender/editors/curve/curve_intern.h2
-rw-r--r--source/blender/editors/curve/curve_ops.c3
-rw-r--r--source/blender/editors/curve/editcurve.c131
-rw-r--r--source/blender/editors/curve/editcurve_paint.c110
-rw-r--r--source/blender/editors/curve/editfont.c74
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt1
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c73
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c35
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c927
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h97
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c1142
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c13
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c65
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c68
-rw-r--r--source/blender/editors/include/ED_anim_api.h11
-rw-r--r--source/blender/editors/include/ED_armature.h12
-rw-r--r--source/blender/editors/include/ED_clip.h2
-rw-r--r--source/blender/editors/include/ED_image.h2
-rw-r--r--source/blender/editors/include/ED_mesh.h1
-rw-r--r--source/blender/editors/include/ED_node.h2
-rw-r--r--source/blender/editors/include/ED_screen.h2
-rw-r--r--source/blender/editors/include/ED_transform.h15
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h12
-rw-r--r--source/blender/editors/include/ED_util.h1
-rw-r--r--source/blender/editors/include/ED_view3d.h48
-rw-r--r--source/blender/editors/include/UI_icons.h15
-rw-r--r--source/blender/editors/include/UI_interface.h13
-rw-r--r--source/blender/editors/include/UI_resources.h1
-rw-r--r--source/blender/editors/include/UI_view2d.h1
-rw-r--r--source/blender/editors/interface/interface.c148
-rw-r--r--source/blender/editors/interface/interface_anim.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c25
-rw-r--r--source/blender/editors/interface/interface_handlers.c403
-rw-r--r--source/blender/editors/interface/interface_intern.h7
-rw-r--r--source/blender/editors/interface/interface_layout.c232
-rw-r--r--source/blender/editors/interface/interface_ops.c74
-rw-r--r--source/blender/editors/interface/interface_panel.c22
-rw-r--r--source/blender/editors/interface/interface_regions.c55
-rw-r--r--source/blender/editors/interface/interface_templates.c8
-rw-r--r--source/blender/editors/interface/interface_utils.c27
-rw-r--r--source/blender/editors/interface/interface_widgets.c51
-rw-r--r--source/blender/editors/interface/resources.c18
-rw-r--r--source/blender/editors/interface/view2d.c8
-rw-r--r--source/blender/editors/interface/view2d_ops.c6
-rw-r--r--source/blender/editors/io/io_alembic.c90
-rw-r--r--source/blender/editors/io/io_cache.c34
-rw-r--r--source/blender/editors/io/io_collada.c134
-rw-r--r--source/blender/editors/mask/mask_add.c14
-rw-r--r--source/blender/editors/mask/mask_draw.c7
-rw-r--r--source/blender/editors/mask/mask_ops.c6
-rw-r--r--source/blender/editors/mesh/editface.c67
-rw-r--r--source/blender/editors/mesh/editmesh_add.c4
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c5
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c3
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c54
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c50
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c18
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c4
-rw-r--r--source/blender/editors/mesh/editmesh_select.c6
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c49
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c4
-rw-r--r--source/blender/editors/mesh/mesh_data.c16
-rw-r--r--source/blender/editors/mesh/meshtools.c458
-rw-r--r--source/blender/editors/metaball/mball_edit.c7
-rw-r--r--source/blender/editors/object/object_add.c323
-rw-r--r--source/blender/editors/object/object_bake_api.c54
-rw-r--r--source/blender/editors/object/object_edit.c28
-rw-r--r--source/blender/editors/object/object_group.c3
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_modifier.c64
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/object/object_relations.c332
-rw-r--r--source/blender/editors/object/object_select.c3
-rw-r--r--source/blender/editors/object/object_transform.c57
-rw-r--r--source/blender/editors/object/object_vgroup.c167
-rw-r--r--source/blender/editors/object/object_warp.c3
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c36
-rw-r--r--source/blender/editors/physics/particle_edit.c3
-rw-r--r--source/blender/editors/physics/particle_object.c2
-rw-r--r--source/blender/editors/physics/physics_fluid.c112
-rw-r--r--source/blender/editors/physics/physics_ops.c16
-rw-r--r--source/blender/editors/physics/physics_pointcache.c42
-rw-r--r--source/blender/editors/render/CMakeLists.txt10
-rw-r--r--source/blender/editors/render/render_internal.c20
-rw-r--r--source/blender/editors/render/render_opengl.c52
-rw-r--r--source/blender/editors/render/render_preview.c4
-rw-r--r--source/blender/editors/render/render_shading.c14
-rw-r--r--source/blender/editors/render/render_update.c6
-rw-r--r--source/blender/editors/render/render_view.c19
-rw-r--r--source/blender/editors/screen/area.c2
-rw-r--r--source/blender/editors/screen/glutil.c8
-rw-r--r--source/blender/editors/screen/screen_context.c26
-rw-r--r--source/blender/editors/screen/screen_edit.c51
-rw-r--r--source/blender/editors/screen/screen_ops.c102
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt4
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c22
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c26
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h56
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c309
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c3639
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c574
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c648
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c859
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c311
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c913
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h230
-rw-r--r--source/blender/editors/sound/sound_ops.c4
-rw-r--r--source/blender/editors/space_action/action_draw.c34
-rw-r--r--source/blender/editors/space_action/action_edit.c2
-rw-r--r--source/blender/editors/space_action/action_select.c2
-rw-r--r--source/blender/editors/space_action/space_action.c21
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c2
-rw-r--r--source/blender/editors/space_clip/clip_draw.c16
-rw-r--r--source/blender/editors/space_clip/clip_editor.c12
-rw-r--r--source/blender/editors/space_clip/clip_ops.c2
-rw-r--r--source/blender/editors/space_clip/clip_utils.c5
-rw-r--r--source/blender/editors/space_clip/space_clip.c3
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c9
-rw-r--r--source/blender/editors/space_clip/tracking_ops_plane.c3
-rw-r--r--source/blender/editors/space_clip/tracking_ops_track.c8
-rw-r--r--source/blender/editors/space_console/console_intern.h2
-rw-r--r--source/blender/editors/space_file/file_ops.c5
-rw-r--r--source/blender/editors/space_file/filelist.c87
-rw-r--r--source/blender/editors/space_file/filelist.h3
-rw-r--r--source/blender/editors/space_file/fsmenu.c46
-rw-r--r--source/blender/editors/space_file/space_file.c5
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c32
-rw-r--r--source/blender/editors/space_graph/graph_edit.c6
-rw-r--r--source/blender/editors/space_graph/graph_ops.c2
-rw-r--r--source/blender/editors/space_image/image_buttons.c36
-rw-r--r--source/blender/editors/space_image/image_draw.c2
-rw-r--r--source/blender/editors/space_image/image_ops.c66
-rw-r--r--source/blender/editors/space_info/info_ops.c1
-rw-r--r--source/blender/editors/space_logic/logic_ops.c1
-rw-r--r--source/blender/editors/space_logic/logic_window.c2
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c18
-rw-r--r--source/blender/editors/space_nla/nla_draw.c5
-rw-r--r--source/blender/editors/space_nla/nla_edit.c4
-rw-r--r--source/blender/editors/space_node/drawnode.c70
-rw-r--r--source/blender/editors/space_node/node_add.c22
-rw-r--r--source/blender/editors/space_node/node_buttons.c11
-rw-r--r--source/blender/editors/space_node/node_draw.c137
-rw-r--r--source/blender/editors/space_node/node_edit.c27
-rw-r--r--source/blender/editors/space_node/node_group.c23
-rw-r--r--source/blender/editors/space_node/node_intern.h5
-rw-r--r--source/blender/editors/space_node/node_relationships.c13
-rw-r--r--source/blender/editors/space_node/node_templates.c5
-rw-r--r--source/blender/editors/space_node/node_view.c14
-rw-r--r--source/blender/editors/space_node/space_node.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c47
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c63
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c10
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c35
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c22
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c16
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c23
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c2
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c1
-rw-r--r--source/blender/editors/space_text/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_text/space_text.c4
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c6
-rw-r--r--source/blender/editors/space_text/text_draw.c4
-rw-r--r--source/blender/editors/space_text/text_format.h2
-rw-r--r--source/blender/editors/space_text/text_format_pov.c903
-rw-r--r--source/blender/editors/space_text/text_format_pov_ini.c491
-rw-r--r--source/blender/editors/space_text/text_ops.c2
-rw-r--r--source/blender/editors/space_time/space_time.c2
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c190
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c25
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c13
-rw-r--r--source/blender/editors/space_view3d/drawobject.c112
-rw-r--r--source/blender/editors/space_view3d/drawsimdebug.c20
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c6
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c66
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c27
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c277
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c261
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c25
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h12
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c30
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c14
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c91
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c279
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c15
-rw-r--r--source/blender/editors/transform/transform.c161
-rw-r--r--source/blender/editors/transform/transform.h9
-rw-r--r--source/blender/editors/transform/transform_constraints.c7
-rw-r--r--source/blender/editors/transform/transform_conversions.c322
-rw-r--r--source/blender/editors/transform/transform_generics.c17
-rw-r--r--source/blender/editors/transform/transform_input.c17
-rw-r--r--source/blender/editors/transform/transform_manipulator.c333
-rw-r--r--source/blender/editors/transform/transform_ops.c35
-rw-r--r--source/blender/editors/transform/transform_orientations.c50
-rw-r--r--source/blender/editors/transform/transform_snap.c29
-rw-r--r--source/blender/editors/transform/transform_snap_object.c2308
-rw-r--r--source/blender/editors/util/numinput.c6
-rw-r--r--source/blender/editors/util/undo.c27
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c11
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c3
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c4
-rw-r--r--source/blender/freestyle/intern/application/AppView.cpp6
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp4
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp16
-rw-r--r--source/blender/freestyle/intern/geometry/GeomUtils.cpp2
-rw-r--r--source/blender/freestyle/intern/geometry/matrix_util.h6
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp40
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.h2
-rw-r--r--source/blender/gpu/CMakeLists.txt3
-rw-r--r--source/blender/gpu/GPU_buffers.h45
-rw-r--r--source/blender/gpu/GPU_material.h7
-rw-r--r--source/blender/gpu/GPU_select.h15
-rw-r--r--source/blender/gpu/intern/gpu_basic_shader.c4
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c110
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c4
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c4
-rw-r--r--source/blender/gpu/intern/gpu_debug.c11
-rw-r--r--source/blender/gpu/intern/gpu_draw.c40
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c6
-rw-r--r--source/blender/gpu/intern/gpu_material.c41
-rw-r--r--source/blender/gpu/intern/gpu_select.c278
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c744
-rw-r--r--source/blender/gpu/intern/gpu_select_private.h53
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.c213
-rw-r--r--source/blender/gpu/intern/gpu_shader.c1
-rw-r--r--source/blender/gpu/intern/gpu_texture.c14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl261
-rw-r--r--source/blender/ikplugin/intern/iksolver_plugin.c50
-rw-r--r--source/blender/imbuf/CMakeLists.txt10
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h14
-rw-r--r--source/blender/imbuf/IMB_imbuf.h3
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h23
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h18
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h2
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c15
-rw-r--r--source/blender/imbuf/intern/anim_movie.c51
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c2
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.c15
-rw-r--r--source/blender/imbuf/intern/colormanagement.c259
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp4
-rw-r--r--source/blender/imbuf/intern/filetype.c12
-rw-r--r--source/blender/imbuf/intern/filter.c6
-rw-r--r--source/blender/imbuf/intern/imbuf.h2
-rw-r--r--source/blender/imbuf/intern/iris.c350
-rw-r--r--source/blender/imbuf/intern/jp2.c2
-rw-r--r--source/blender/imbuf/intern/metadata.c2
-rw-r--r--source/blender/imbuf/intern/moviecache.c2
-rw-r--r--source/blender/imbuf/intern/oiio/CMakeLists.txt5
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp4
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp18
-rw-r--r--source/blender/imbuf/intern/png.c5
-rw-r--r--source/blender/imbuf/intern/radiance_hdr.c3
-rw-r--r--source/blender/imbuf/intern/rectop.c49
-rw-r--r--source/blender/imbuf/intern/tiff.c43
-rw-r--r--source/blender/imbuf/intern/util.c39
-rw-r--r--source/blender/makesdna/DNA_ID.h27
-rw-r--r--source/blender/makesdna/DNA_action_types.h12
-rw-r--r--source/blender/makesdna/DNA_anim_types.h2
-rw-r--r--source/blender/makesdna/DNA_brush_types.h41
-rw-r--r--source/blender/makesdna/DNA_cachefile_types.h4
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h5
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h4
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h63
-rw-r--r--source/blender/makesdna/DNA_node_types.h22
-rw-r--r--source/blender/makesdna/DNA_object_fluidsim.h1
-rw-r--r--source/blender/makesdna/DNA_object_force.h1
-rw-r--r--source/blender/makesdna/DNA_object_types.h5
-rw-r--r--source/blender/makesdna/DNA_particle_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h175
-rw-r--r--source/blender/makesdna/DNA_screen_types.h2
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h2
-rw-r--r--source/blender/makesdna/DNA_space_types.h4
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h144
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h3
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c2
-rw-r--r--source/blender/makesrna/RNA_access.h13
-rw-r--r--source/blender/makesrna/RNA_define.h15
-rw-r--r--source/blender/makesrna/RNA_enum_types.h2
-rw-r--r--source/blender/makesrna/RNA_types.h59
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt13
-rw-r--r--source/blender/makesrna/intern/makesrna.c100
-rw-r--r--source/blender/makesrna/intern/rna_ID.c26
-rw-r--r--source/blender/makesrna/intern/rna_access.c227
-rw-r--r--source/blender/makesrna/intern/rna_action.c25
-rw-r--r--source/blender/makesrna/intern/rna_actuator.c3
-rw-r--r--source/blender/makesrna/intern/rna_actuator_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_animation.c39
-rw-r--r--source/blender/makesrna/intern/rna_animviz.c29
-rw-r--r--source/blender/makesrna/intern/rna_armature.c22
-rw-r--r--source/blender/makesrna/intern/rna_armature_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_brush.c41
-rw-r--r--source/blender/makesrna/intern/rna_color.c33
-rw-r--r--source/blender/makesrna/intern/rna_controller.c1
-rw-r--r--source/blender/makesrna/intern/rna_curve.c14
-rw-r--r--source/blender/makesrna/intern/rna_curve_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_define.c222
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c5
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c4
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c68
-rw-r--r--source/blender/makesrna/intern/rna_fcurve_api.c8
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c8
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c79
-rw-r--r--source/blender/makesrna/intern/rna_group.c4
-rw-r--r--source/blender/makesrna/intern/rna_image.c4
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c13
-rw-r--r--source/blender/makesrna/intern/rna_internal.h1
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h25
-rw-r--r--source/blender/makesrna/intern/rna_key.c9
-rw-r--r--source/blender/makesrna/intern/rna_lattice_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c36
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c516
-rw-r--r--source/blender/makesrna/intern/rna_mask.c12
-rw-r--r--source/blender/makesrna/intern/rna_material.c4
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c89
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c21
-rw-r--r--source/blender/makesrna/intern/rna_meta.c4
-rw-r--r--source/blender/makesrna/intern/rna_meta_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c101
-rw-r--r--source/blender/makesrna/intern/rna_nla.c22
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c417
-rw-r--r--source/blender/makesrna/intern/rna_object.c64
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c114
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c7
-rw-r--r--source/blender/makesrna/intern/rna_palette.c4
-rw-r--r--source/blender/makesrna/intern/rna_particle.c145
-rw-r--r--source/blender/makesrna/intern/rna_pose.c25
-rw-r--r--source/blender/makesrna/intern/rna_pose_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_property.c1
-rw-r--r--source/blender/makesrna/intern/rna_render.c320
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c44
-rw-r--r--source/blender/makesrna/intern/rna_rna.c68
-rw-r--r--source/blender/makesrna/intern/rna_scene.c517
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c169
-rw-r--r--source/blender/makesrna/intern/rna_screen.c12
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c36
-rw-r--r--source/blender/makesrna/intern/rna_sensor.c1
-rw-r--r--source/blender/makesrna/intern/rna_sensor_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c88
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c68
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c4
-rw-r--r--source/blender/makesrna/intern/rna_space.c356
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c10
-rw-r--r--source/blender/makesrna/intern/rna_text_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_texture.c2
-rw-r--r--source/blender/makesrna/intern/rna_texture_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c22
-rw-r--r--source/blender/makesrna/intern/rna_ui.c108
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c127
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c104
-rw-r--r--source/blender/makesrna/intern/rna_wm.c317
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c117
-rw-r--r--source/blender/modifiers/CMakeLists.txt5
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c10
-rw-r--r--source/blender/modifiers/intern/MOD_array.c51
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c14
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c38
-rw-r--r--source/blender/modifiers/intern/MOD_boolean_util.c3
-rw-r--r--source/blender/modifiers/intern/MOD_build.c2
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c5
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c12
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c5
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c9
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c11
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c220
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c28
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c1
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c6
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim.c15
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c31
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c2
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c4
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c4
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_mdd.c5
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_pc2.c6
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_util.c2
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c8
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c31
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c12
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c2
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c31
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c4
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c69
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c4
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c2
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c2
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c21
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c7
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c2
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c1
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c1231
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_util.c1
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c10
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c4
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c12
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c12
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c13
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c15
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c14
-rw-r--r--source/blender/nodes/CMakeLists.txt5
-rw-r--r--source/blender/nodes/NOD_composite.h4
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h5
-rw-r--r--source/blender/nodes/composite/node_composite_tree.c35
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bilateralblur.c1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.c5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_directionalblur.c1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_glare.c3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hueSatVal.c16
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c544
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switchview.c1
-rw-r--r--source/blender/nodes/intern/node_exec.c3
-rw-r--r--source/blender/nodes/shader/node_shader_util.c52
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c114
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_fresnel.c32
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_layer_weight.c43
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_path.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_object_info.c12
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.c2
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp51
-rw-r--r--source/blender/physics/intern/implicit.h10
-rw-r--r--source/blender/physics/intern/implicit_blender.c34
-rw-r--r--source/blender/python/BPY_extern.h3
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c43
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c78
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c5
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.c11
-rw-r--r--source/blender/python/bmesh/bmesh_py_utils.c4
-rw-r--r--source/blender/python/generic/bgl.c135
-rw-r--r--source/blender/python/generic/bpy_internal_import.c25
-rw-r--r--source/blender/python/generic/idprop_py_api.c442
-rw-r--r--source/blender/python/generic/py_capi_utils.c238
-rw-r--r--source/blender/python/generic/py_capi_utils.h50
-rw-r--r--source/blender/python/generic/python_utildefines.h6
-rw-r--r--source/blender/python/intern/CMakeLists.txt13
-rw-r--r--source/blender/python/intern/bpy.c27
-rw-r--r--source/blender/python/intern/bpy_app.c24
-rw-r--r--source/blender/python/intern/bpy_app_alembic.c6
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c7
-rw-r--r--source/blender/python/intern/bpy_app_ffmpeg.c5
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c12
-rw-r--r--source/blender/python/intern/bpy_app_ocio.c7
-rw-r--r--source/blender/python/intern/bpy_app_oiio.c7
-rw-r--r--source/blender/python/intern/bpy_app_opensubdiv.c110
-rw-r--r--source/blender/python/intern/bpy_app_opensubdiv.h (renamed from source/blender/depsgraph/util/deg_util_hash.h)23
-rw-r--r--source/blender/python/intern/bpy_app_openvdb.c7
-rw-r--r--source/blender/python/intern/bpy_app_sdl.c8
-rw-r--r--source/blender/python/intern/bpy_interface.c62
-rw-r--r--source/blender/python/intern/bpy_library_load.c14
-rw-r--r--source/blender/python/intern/bpy_library_write.c21
-rw-r--r--source/blender/python/intern/bpy_operator.c2
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c14
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.h4
-rw-r--r--source/blender/python/intern/bpy_props.c422
-rw-r--r--source/blender/python/intern/bpy_props.h4
-rw-r--r--source/blender/python/intern/bpy_rna.c256
-rw-r--r--source/blender/python/intern/bpy_rna.h1
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c104
-rw-r--r--source/blender/python/intern/bpy_rna_array.c4
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c10
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c10
-rw-r--r--source/blender/python/intern/bpy_util.h4
-rw-r--r--source/blender/python/intern/bpy_utils_units.c26
-rw-r--r--source/blender/python/intern/gpu.c14
-rw-r--r--source/blender/python/intern/gpu_offscreen.c36
-rw-r--r--source/blender/python/mathutils/mathutils.c39
-rw-r--r--source/blender/python/mathutils/mathutils.h11
-rw-r--r--source/blender/python/mathutils/mathutils_Color.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.c4
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c97
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h5
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c890
-rw-r--r--source/blender/python/mathutils/mathutils_bvhtree.c10
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c2
-rw-r--r--source/blender/quicktime/apple/qtkit_export.m884
-rw-r--r--source/blender/quicktime/apple/qtkit_import.m400
-rw-r--r--source/blender/quicktime/quicktime_export.h162
-rw-r--r--source/blender/quicktime/quicktime_import.h63
-rw-r--r--source/blender/render/CMakeLists.txt16
-rw-r--r--source/blender/render/extern/include/RE_engine.h7
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h28
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h2
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h6
-rw-r--r--source/blender/render/intern/include/render_result.h7
-rw-r--r--source/blender/render/intern/include/render_types.h4
-rw-r--r--source/blender/render/intern/include/rendercore.h8
-rw-r--r--source/blender/render/intern/include/shading.h4
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.cpp12
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.h5
-rw-r--r--source/blender/render/intern/source/bake_api.c4
-rw-r--r--source/blender/render/intern/source/convertblender.c41
-rw-r--r--source/blender/render/intern/source/envmap.c16
-rw-r--r--source/blender/render/intern/source/external_engine.c41
-rw-r--r--source/blender/render/intern/source/imagetexture.c4
-rw-r--r--source/blender/render/intern/source/initrender.c4
-rw-r--r--source/blender/render/intern/source/occlusion.c13
-rw-r--r--source/blender/render/intern/source/pipeline.c122
-rw-r--r--source/blender/render/intern/source/pointdensity.c9
-rw-r--r--source/blender/render/intern/source/render_result.c669
-rw-r--r--source/blender/render/intern/source/render_texture.c71
-rw-r--r--source/blender/render/intern/source/rendercore.c410
-rw-r--r--source/blender/render/intern/source/renderdatabase.c9
-rw-r--r--source/blender/render/intern/source/shadeinput.c6
-rw-r--r--source/blender/render/intern/source/shadeoutput.c33
-rw-r--r--source/blender/render/intern/source/sunsky.c2
-rw-r--r--source/blender/render/intern/source/volume_precache.c10
-rw-r--r--source/blender/render/intern/source/volumetric.c6
-rw-r--r--source/blender/render/intern/source/zbuf.c252
-rw-r--r--source/blender/windowmanager/CMakeLists.txt14
-rw-r--r--source/blender/windowmanager/WM_api.h9
-rw-r--r--source/blender/windowmanager/WM_types.h9
-rw-r--r--source/blender/windowmanager/intern/wm.c45
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c8
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c60
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c118
-rw-r--r--source/blender/windowmanager/intern/wm_files.c363
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c5
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c5
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c15
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c7
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c149
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c5
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c32
-rw-r--r--source/blender/windowmanager/intern/wm_window.c107
-rw-r--r--source/blender/windowmanager/wm.h3
-rw-r--r--source/blender/windowmanager/wm_draw.h2
-rw-r--r--source/blender/windowmanager/wm_event_system.h5
-rw-r--r--source/blender/windowmanager/wm_files.h5
-rw-r--r--source/blender/windowmanager/wm_window.h2
-rw-r--r--source/blenderplayer/CMakeLists.txt43
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c74
-rw-r--r--source/creator/CMakeLists.txt195
-rw-r--r--source/creator/creator_args.c204
-rw-r--r--source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp6
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp2
-rw-r--r--source/gameengine/Expressions/intern/HashedPtr.cpp4
-rw-r--r--source/gameengine/Expressions/intern/InputParser.cpp2
-rw-r--r--source/gameengine/Expressions/intern/PyObjectPlus.cpp8
-rw-r--r--source/gameengine/GameLogic/CMakeLists.txt3
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp6
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp2
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.cpp4
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Canvas.h2
-rw-r--r--source/gameengine/GamePlayer/common/GPC_MouseDevice.h2
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.cpp2
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_ghost.cpp4
-rw-r--r--source/gameengine/Ketsji/BL_BlenderShader.cpp2
-rw-r--r--source/gameengine/Ketsji/BL_Shader.cpp2
-rw-r--r--source/gameengine/Ketsji/BL_Texture.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_Dome.h2
-rw-r--r--source/gameengine/Ketsji/KX_FontObject.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_IPO_SGController.cpp4
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp6
-rw-r--r--source/gameengine/Ketsji/KX_ObstacleSimulation.cpp1
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.cpp7
-rw-r--r--source/gameengine/Ketsji/KX_SoundActuator.cpp4
-rw-r--r--source/gameengine/Physics/Bullet/CMakeLists.txt1
-rw-r--r--source/gameengine/Rasterizer/CMakeLists.txt1
-rw-r--r--source/gameengine/Rasterizer/RAS_2DFilterManager.cpp4
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp6
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h2
-rw-r--r--source/gameengine/VideoTexture/FilterBase.cpp1
-rw-r--r--source/gameengine/VideoTexture/FilterColor.cpp2
-rw-r--r--source/gameengine/VideoTexture/FilterColor.h4
-rw-r--r--source/gameengine/VideoTexture/ImageBase.cpp3
-rw-r--r--source/gameengine/VideoTexture/ImageBase.h2
-rw-r--r--source/gameengine/VideoTexture/ImageRender.cpp3
-rw-r--r--source/gameengine/VideoTexture/ImageViewport.cpp2
-rw-r--r--source/gameengine/VideoTexture/Texture.cpp2
-rw-r--r--source/gameengine/VideoTexture/VideoDeckLink.h2
m---------source/tools0
1077 files changed, 46225 insertions, 28834 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 6f2b78e0845..818d4cd3d89 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -138,10 +138,6 @@ if(WITH_CODEC_AVI)
add_subdirectory(avi)
endif()
-if(WITH_CODEC_QUICKTIME)
- add_subdirectory(quicktime)
-endif()
-
if(WITH_PYTHON)
add_subdirectory(python)
endif()
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
index e92d5f2d9f7..70250310213 100644
--- a/source/blender/alembic/ABC_alembic.h
+++ b/source/blender/alembic/ABC_alembic.h
@@ -47,47 +47,63 @@ struct AlembicExportParams {
double frame_start;
double frame_end;
- double frame_step_xform;
- double frame_step_shape;
+ unsigned int frame_samples_xform;
+ unsigned int frame_samples_shape;
double shutter_open;
double shutter_close;
- /* bools */
- unsigned int selected_only : 1;
- unsigned int uvs : 1;
- unsigned int normals : 1;
- unsigned int vcolors : 1;
- unsigned int apply_subdiv : 1;
- unsigned int flatten_hierarchy : 1;
- unsigned int visible_layers_only : 1;
- unsigned int renderable_only : 1;
- unsigned int face_sets : 1;
- unsigned int use_subdiv_schema : 1;
- unsigned int packuv : 1;
- unsigned int triangulate : 1;
+ bool selected_only;
+ bool uvs;
+ bool normals;
+ bool vcolors;
+ bool apply_subdiv;
+ bool flatten_hierarchy;
+ bool visible_layers_only;
+ bool renderable_only;
+ bool face_sets;
+ bool use_subdiv_schema;
+ bool packuv;
+ bool triangulate;
+ bool export_hair;
+ bool export_particles;
unsigned int compression_type : 1;
+ /* See MOD_TRIANGULATE_NGON_xxx and MOD_TRIANGULATE_QUAD_xxx
+ * in DNA_modifier_types.h */
int quad_method;
int ngon_method;
+
float global_scale;
};
-void ABC_export(
+/* The ABC_export and ABC_import functions both take a as_background_job
+ * parameter, and return a boolean.
+ *
+ * When as_background_job=true, returns false immediately after scheduling
+ * a background job.
+ *
+ * When as_background_job=false, performs the export synchronously, and returns
+ * true when the export was ok, and false if there were any errors.
+ */
+
+bool ABC_export(
struct Scene *scene,
struct bContext *C,
const char *filepath,
- const struct AlembicExportParams *params);
+ const struct AlembicExportParams *params,
+ bool as_background_job);
-void ABC_import(struct bContext *C,
+bool ABC_import(struct bContext *C,
const char *filepath,
float scale,
bool is_sequence,
bool set_frame_range,
int sequence_len,
int offset,
- bool validate_meshes);
+ bool validate_meshes,
+ bool as_background_job);
AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths);
@@ -105,6 +121,7 @@ struct DerivedMesh *ABC_read_mesh(struct CacheReader *reader,
const char **err_str,
int flags);
+void CacheReader_incref(struct CacheReader *reader);
void CacheReader_free(struct CacheReader *reader);
struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *handle,
diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt
index ad85f79ef2e..a6e0be6a7f3 100644
--- a/source/blender/alembic/CMakeLists.txt
+++ b/source/blender/alembic/CMakeLists.txt
@@ -39,14 +39,10 @@ set(INC
set(INC_SYS
${ALEMBIC_INCLUDE_DIRS}
+ ${BOOST_INCLUDE_DIR}
${HDF5_INCLUDE_DIRS}
${OPENEXR_INCLUDE_DIRS}
)
-if(APPLE OR WIN32)
- list(APPEND INC_SYS
- ${BOOST_INCLUDE_DIR}
- )
-endif()
set(SRC
intern/abc_archive.cc
diff --git a/source/blender/alembic/intern/abc_archive.cc b/source/blender/alembic/intern/abc_archive.cc
index 0985a06d732..bd16196cb78 100644
--- a/source/blender/alembic/intern/abc_archive.cc
+++ b/source/blender/alembic/intern/abc_archive.cc
@@ -23,11 +23,17 @@
*/
#include "abc_archive.h"
+extern "C"
+{
+ #include "BKE_blender_version.h"
+}
#ifdef WIN32
# include "utfconv.h"
#endif
+#include <fstream>
+
using Alembic::Abc::Exception;
using Alembic::Abc::ErrorHandler;
using Alembic::Abc::IArchive;
@@ -38,8 +44,9 @@ static IArchive open_archive(const std::string &filename,
const std::vector<std::istream *> &input_streams,
bool &is_hdf5)
{
+ is_hdf5 = false;
+
try {
- is_hdf5 = false;
Alembic::AbcCoreOgawa::ReadArchive archive_reader(input_streams);
return IArchive(archive_reader(filename),
@@ -63,6 +70,27 @@ static IArchive open_archive(const std::string &filename,
return IArchive();
}
#else
+ /* Inspect the file to see whether it's really a HDF5 file. */
+ char header[4]; /* char(0x89) + "HDF" */
+ std::ifstream the_file(filename.c_str(), std::ios::in | std::ios::binary);
+ if (!the_file) {
+ std::cerr << "Unable to open " << filename << std::endl;
+ }
+ else if (!the_file.read(header, sizeof(header))) {
+ std::cerr << "Unable to read from " << filename << std::endl;
+ }
+ else if (strncmp(header + 1, "HDF", 3)) {
+ std::cerr << filename << " has an unknown file format, unable to read." << std::endl;
+ }
+ else {
+ is_hdf5 = true;
+ std::cerr << filename << " is in the obsolete HDF5 format, unable to read." << std::endl;
+ }
+
+ if (the_file.is_open()) {
+ the_file.close();
+ }
+
return IArchive();
#endif
}
@@ -83,16 +111,20 @@ ArchiveReader::ArchiveReader(const char *filename)
m_streams.push_back(&m_infile);
- bool is_hdf5;
- m_archive = open_archive(filename, m_streams, is_hdf5);
+ m_archive = open_archive(filename, m_streams, m_is_hdf5);
/* We can't open an HDF5 file from a stream, so close it. */
- if (is_hdf5) {
+ if (m_is_hdf5) {
m_infile.close();
m_streams.clear();
}
}
+bool ArchiveReader::is_hdf5() const
+{
+ return m_is_hdf5;
+}
+
bool ArchiveReader::valid() const
{
return m_archive.valid();
@@ -113,25 +145,26 @@ static OArchive create_archive(std::ostream *ostream,
Alembic::Abc::MetaData &md,
bool ogawa)
{
- md.set(Alembic::Abc::kApplicationNameKey, "Blender");
+ md.set(Alembic::Abc::kApplicationNameKey, "Blender");
md.set(Alembic::Abc::kUserDescriptionKey, scene_name);
+ md.set("blender_version", versionstr);
- time_t raw_time;
- time(&raw_time);
- char buffer[128];
+ time_t raw_time;
+ time(&raw_time);
+ char buffer[128];
#if defined _WIN32 || defined _WIN64
- ctime_s(buffer, 128, &raw_time);
+ ctime_s(buffer, 128, &raw_time);
#else
- ctime_r(&raw_time, buffer);
+ ctime_r(&raw_time, buffer);
#endif
- const std::size_t buffer_len = strlen(buffer);
- if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') {
- buffer[buffer_len - 1] = '\0';
- }
+ const std::size_t buffer_len = strlen(buffer);
+ if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') {
+ buffer[buffer_len - 1] = '\0';
+ }
- md.set(Alembic::Abc::kDateWrittenKey, buffer);
+ md.set(Alembic::Abc::kDateWrittenKey, buffer);
ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy;
diff --git a/source/blender/alembic/intern/abc_archive.h b/source/blender/alembic/intern/abc_archive.h
index d412574b736..84309fbc9df 100644
--- a/source/blender/alembic/intern/abc_archive.h
+++ b/source/blender/alembic/intern/abc_archive.h
@@ -44,12 +44,21 @@ class ArchiveReader {
Alembic::Abc::IArchive m_archive;
std::ifstream m_infile;
std::vector<std::istream *> m_streams;
+ bool m_is_hdf5;
public:
explicit ArchiveReader(const char *filename);
bool valid() const;
+ /**
+ * Returns true when either Blender is compiled with HDF5 support and
+ * the archive was succesfully opened (valid() will also return true),
+ * or when Blender was built without HDF5 support but a HDF5 file was
+ * detected (valid() will return false).
+ */
+ bool is_hdf5() const;
+
Alembic::Abc::IObject getTop();
};
diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc
index d5271e3ca31..16416205983 100644
--- a/source/blender/alembic/intern/abc_camera.cc
+++ b/source/blender/alembic/intern/abc_camera.cc
@@ -117,11 +117,27 @@ bool AbcCameraReader::valid() const
return m_schema.valid();
}
-void AbcCameraReader::readObjectData(Main *bmain, float time)
+bool AbcCameraReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::ICamera::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to Camera when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_CAMERA) {
+ *err_str = "Object type mismatch, Alembic object path points to Camera.";
+ return false;
+ }
+
+ return true;
+}
+
+void AbcCameraReader::readObjectData(Main *bmain, const ISampleSelector &sample_sel)
{
Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, m_data_name.c_str()));
- ISampleSelector sample_sel(time);
CameraSample cam_sample;
m_schema.get(cam_sample, sample_sel);
@@ -138,11 +154,11 @@ void AbcCameraReader::readObjectData(Main *bmain, float time)
bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel);
}
- const float lens = cam_sample.getFocalLength();
- const float apperture_x = cam_sample.getHorizontalAperture();
- const float apperture_y = cam_sample.getVerticalAperture();
- const float h_film_offset = cam_sample.getHorizontalFilmOffset();
- const float v_film_offset = cam_sample.getVerticalFilmOffset();
+ const float lens = static_cast<float>(cam_sample.getFocalLength());
+ const float apperture_x = static_cast<float>(cam_sample.getHorizontalAperture());
+ const float apperture_y = static_cast<float>(cam_sample.getVerticalAperture());
+ const float h_film_offset = static_cast<float>(cam_sample.getHorizontalFilmOffset());
+ const float v_film_offset = static_cast<float>(cam_sample.getVerticalFilmOffset());
const float film_aspect = apperture_x / apperture_y;
bcam->lens = lens;
@@ -150,10 +166,10 @@ void AbcCameraReader::readObjectData(Main *bmain, float time)
bcam->sensor_y = apperture_y * 10;
bcam->shiftx = h_film_offset / apperture_x;
bcam->shifty = v_film_offset / apperture_y / film_aspect;
- bcam->clipsta = max_ff(0.1f, cam_sample.getNearClippingPlane());
- bcam->clipend = cam_sample.getFarClippingPlane();
- bcam->gpu_dof.focus_distance = cam_sample.getFocusDistance();
- bcam->gpu_dof.fstop = cam_sample.getFStop();
+ bcam->clipsta = max_ff(0.1f, static_cast<float>(cam_sample.getNearClippingPlane()));
+ bcam->clipend = static_cast<float>(cam_sample.getFarClippingPlane());
+ bcam->gpu_dof.focus_distance = static_cast<float>(cam_sample.getFocusDistance());
+ bcam->gpu_dof.fstop = static_cast<float>(cam_sample.getFStop());
m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str());
m_object->data = bcam;
diff --git a/source/blender/alembic/intern/abc_camera.h b/source/blender/alembic/intern/abc_camera.h
index fafb4d3eb39..16c5cccd5ea 100644
--- a/source/blender/alembic/intern/abc_camera.h
+++ b/source/blender/alembic/intern/abc_camera.h
@@ -54,8 +54,11 @@ public:
AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const;
- void readObjectData(Main *bmain, float time);
+ void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
};
-#endif /* __ABC_CAMERA_H__ */ \ No newline at end of file
+#endif /* __ABC_CAMERA_H__ */
diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc
index 7e5ea3b1853..f73fe957fea 100644
--- a/source/blender/alembic/intern/abc_curves.cc
+++ b/source/blender/alembic/intern/abc_curves.cc
@@ -49,19 +49,26 @@ using Alembic::Abc::Int32ArraySamplePtr;
using Alembic::Abc::FloatArraySamplePtr;
using Alembic::Abc::P3fArraySamplePtr;
using Alembic::Abc::UcharArraySamplePtr;
+using Alembic::Abc::PropertyHeader;
+using Alembic::AbcGeom::ICompoundProperty;
using Alembic::AbcGeom::ICurves;
using Alembic::AbcGeom::ICurvesSchema;
using Alembic::AbcGeom::IFloatGeomParam;
+using Alembic::AbcGeom::IInt16Property;
using Alembic::AbcGeom::ISampleSelector;
using Alembic::AbcGeom::kWrapExisting;
using Alembic::AbcGeom::CurvePeriodicity;
+using Alembic::AbcGeom::OCompoundProperty;
using Alembic::AbcGeom::OCurves;
using Alembic::AbcGeom::OCurvesSchema;
+using Alembic::AbcGeom::OInt16Property;
using Alembic::AbcGeom::ON3fGeomParam;
using Alembic::AbcGeom::OV2fGeomParam;
+#define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution"
+
/* ************************************************************************** */
AbcCurveWriter::AbcCurveWriter(Scene *scene,
@@ -73,6 +80,11 @@ AbcCurveWriter::AbcCurveWriter(Scene *scene,
{
OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
m_schema = curves.getSchema();
+
+ Curve *cu = static_cast<Curve *>(m_object->data);
+ OCompoundProperty user_props = m_schema.getUserProperties();
+ OInt16Property user_prop_resolu(user_props, ABC_CURVE_RESOLUTION_U_PROPNAME);
+ user_prop_resolu.set(cu->resolu);
}
void AbcCurveWriter::do_write()
@@ -95,14 +107,14 @@ void AbcCurveWriter::do_write()
for (; nurbs; nurbs = nurbs->next) {
if (nurbs->bp) {
curve_basis = Alembic::AbcGeom::kNoBasis;
- curve_type = Alembic::AbcGeom::kLinear;
+ curve_type = Alembic::AbcGeom::kVariableOrder;
const int totpoint = nurbs->pntsu * nurbs->pntsv;
const BPoint *point = nurbs->bp;
for (int i = 0; i < totpoint; ++i, ++point) {
- copy_zup_yup(temp_vert.getValue(), point->vec);
+ copy_yup_from_zup(temp_vert.getValue(), point->vec);
verts.push_back(temp_vert);
weights.push_back(point->vec[3]);
widths.push_back(point->radius);
@@ -118,7 +130,7 @@ void AbcCurveWriter::do_write()
/* TODO(kevin): store info about handles, Alembic doesn't have this. */
for (int i = 0; i < totpoint; ++i, ++bezier) {
- copy_zup_yup(temp_vert.getValue(), bezier->vec[1]);
+ copy_yup_from_zup(temp_vert.getValue(), bezier->vec[1]);
verts.push_back(temp_vert);
widths.push_back(bezier->radius);
}
@@ -160,7 +172,7 @@ void AbcCurveWriter::do_write()
}
}
- orders.push_back(nurbs->orderu + 1);
+ orders.push_back(nurbs->orderu);
vert_counts.push_back(verts.size());
}
@@ -199,17 +211,44 @@ bool AbcCurveReader::valid() const
return m_curves_schema.valid();
}
-void AbcCurveReader::readObjectData(Main *bmain, float time)
+bool AbcCurveReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::ICurves::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to Curves when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_CURVE) {
+ *err_str = "Object type mismatch, Alembic object path points to Curves.";
+ return false;
+ }
+
+ return true;
+}
+
+void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVE);
cu->flag |= CU_DEFORM_FILL | CU_3D;
cu->actvert = CU_ACT_NONE;
+ cu->resolu = 1;
+
+ ICompoundProperty user_props = m_curves_schema.getUserProperties();
+ if (user_props) {
+ const PropertyHeader *header = user_props.getPropertyHeader(ABC_CURVE_RESOLUTION_U_PROPNAME);
+ if (header != NULL && header->isScalar() && IInt16Property::matches(*header)) {
+ IInt16Property resolu(user_props, header->getName());
+ cu->resolu = resolu.getValue(sample_sel);
+ }
+ }
m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str());
m_object->data = cu;
- read_curve_sample(cu, m_curves_schema, time);
+ read_curve_sample(cu, m_curves_schema, sample_sel);
if (has_animations(m_curves_schema, m_settings)) {
addCacheModifier();
@@ -218,9 +257,8 @@ void AbcCurveReader::readObjectData(Main *bmain, float time)
/* ************************************************************************** */
-void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
+void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel)
{
- const ISampleSelector sample_sel(time);
ICurvesSchema::Sample smp = schema.getValue(sample_sel);
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
const P3fArraySamplePtr positions = smp.getPositions();
@@ -250,13 +288,19 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
nu->pntsv = 1;
nu->flag |= CU_SMOOTH;
- nu->orderu = num_verts;
-
- if (smp.getType() == Alembic::AbcGeom::kCubic) {
- nu->orderu = 3;
- }
- else if (orders && orders->size() > i) {
- nu->orderu = static_cast<short>((*orders)[i] - 1);
+ switch (smp.getType()) {
+ case Alembic::AbcGeom::kCubic:
+ nu->orderu = 4;
+ break;
+ case Alembic::AbcGeom::kVariableOrder:
+ if (orders && orders->size() > i) {
+ nu->orderu = static_cast<short>((*orders)[i]);
+ break;
+ }
+ ATTR_FALLTHROUGH;
+ case Alembic::AbcGeom::kLinear:
+ default:
+ nu->orderu = 2;
}
if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
@@ -322,7 +366,7 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
weight = (*weights)[idx];
}
- copy_yup_zup(bp->vec, pos.getValue());
+ copy_zup_from_yup(bp->vec, pos.getValue());
bp->vec[3] = weight;
bp->f1 = SELECT;
bp->radius = radius;
@@ -361,9 +405,11 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
* object directly and create a new DerivedMesh from that. Also we might need to
* create new or delete existing NURBS in the curve.
*/
-DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/)
+DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh * /*dm*/,
+ const ISampleSelector &sample_sel,
+ int /*read_flag*/,
+ const char ** /*err_str*/)
{
- ISampleSelector sample_sel(time);
const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel);
const P3fArraySamplePtr &positions = sample.getPositions();
@@ -377,7 +423,7 @@ DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float t
if (curve_count != num_vertices->size()) {
BKE_nurbList_free(&curve->nurb);
- read_curve_sample(curve, m_curves_schema, time);
+ read_curve_sample(curve, m_curves_schema, sample_sel);
}
else {
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
@@ -389,7 +435,7 @@ DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float t
for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) {
const Imath::V3f &pos = (*positions)[vertex_idx];
- copy_yup_zup(point->vec, pos.getValue());
+ copy_zup_from_yup(point->vec, pos.getValue());
}
}
else if (nurbs->bezt) {
@@ -397,7 +443,7 @@ DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float t
for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) {
const Imath::V3f &pos = (*positions)[vertex_idx];
- copy_yup_zup(bezier->vec[1], pos.getValue());
+ copy_zup_from_yup(bezier->vec[1], pos.getValue());
}
}
}
diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h
index 979ee8af639..a9231f947b2 100644
--- a/source/blender/alembic/intern/abc_curves.h
+++ b/source/blender/alembic/intern/abc_curves.h
@@ -54,13 +54,21 @@ public:
AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const;
- void readObjectData(Main *bmain, float time);
- DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int);
+ void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
+ DerivedMesh *read_derivedmesh(DerivedMesh *dm,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
};
/* ************************************************************************** */
-void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time);
+void read_curve_sample(Curve *cu,
+ const Alembic::AbcGeom::ICurvesSchema &schema,
+ const Alembic::Abc::ISampleSelector &sample_selector);
#endif /* __ABC_CURVES_H__ */
diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc
index ebf1b2ba96e..d6e7a80d174 100644
--- a/source/blender/alembic/intern/abc_customdata.cc
+++ b/source/blender/alembic/intern/abc_customdata.cc
@@ -227,48 +227,6 @@ using Alembic::AbcGeom::IC3fGeomParam;
using Alembic::AbcGeom::IC4fGeomParam;
using Alembic::AbcGeom::IV2fGeomParam;
-static void read_mcols(const CDStreamConfig &config, void *data,
- const C3fArraySamplePtr &c3f_ptr, const C4fArraySamplePtr &c4f_ptr)
-{
- MCol *cfaces = static_cast<MCol *>(data);
- MPoly *polys = config.mpoly;
- MLoop *mloops = config.mloop;
-
- if (c3f_ptr) {
- for (int i = 0; i < config.totpoly; ++i) {
- MPoly *p = &polys[i];
- MCol *cface = &cfaces[p->loopstart + p->totloop];
- MLoop *mloop = &mloops[p->loopstart + p->totloop];
-
- for (int j = 0; j < p->totloop; ++j) {
- cface--;
- mloop--;
- const Imath::C3f &color = (*c3f_ptr)[mloop->v];
- cface->a = FTOCHAR(color[0]);
- cface->r = FTOCHAR(color[1]);
- cface->g = FTOCHAR(color[2]);
- cface->b = 255;
- }
- }
- }
- else if (c4f_ptr) {
- for (int i = 0; i < config.totpoly; ++i) {
- MPoly *p = &polys[i];
- MCol *cface = &cfaces[p->loopstart + p->totloop];
- MLoop *mloop = &mloops[p->loopstart + p->totloop];
-
- for (int j = 0; j < p->totloop; ++j) {
- cface--;
- mloop--;
- const Imath::C4f &color = (*c4f_ptr)[mloop->v];
- cface->a = FTOCHAR(color[0]);
- cface->r = FTOCHAR(color[1]);
- cface->g = FTOCHAR(color[2]);
- cface->b = FTOCHAR(color[3]);
- }
- }
- }
-}
static void read_uvs(const CDStreamConfig &config, void *data,
const Alembic::AbcGeom::V2fArraySamplePtr &uvs,
@@ -294,55 +252,151 @@ static void read_uvs(const CDStreamConfig &config, void *data,
}
}
-static void read_custom_data_ex(const ICompoundProperty &prop,
- const PropertyHeader &prop_header,
- const CDStreamConfig &config,
- const Alembic::Abc::ISampleSelector &iss,
- int data_type)
+static size_t mcols_out_of_bounds_check(
+ const size_t color_index,
+ const size_t array_size,
+ const std::string & iobject_full_name,
+ const PropertyHeader &prop_header,
+ bool &r_bounds_warning_given)
{
- if (data_type == CD_MLOOPCOL) {
- C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr();
- C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr();
+ if (color_index < array_size) {
+ return color_index;
+ }
- if (IC3fGeomParam::matches(prop_header)) {
- IC3fGeomParam color_param(prop, prop_header.getName());
- IC3fGeomParam::Sample sample;
- color_param.getIndexed(sample, iss);
+ if (!r_bounds_warning_given) {
+ std::cerr << "Alembic: color index out of bounds "
+ "reading face colors for object "
+ << iobject_full_name
+ << ", property "
+ << prop_header.getName() << std::endl;
+ r_bounds_warning_given = true;
+ }
- c3f_ptr = sample.getVals();
- }
- else if (IC4fGeomParam::matches(prop_header)) {
- IC4fGeomParam color_param(prop, prop_header.getName());
- IC4fGeomParam::Sample sample;
- color_param.getIndexed(sample, iss);
+ return 0;
+}
- c4f_ptr = sample.getVals();
- }
+static void read_custom_data_mcols(const std::string & iobject_full_name,
+ const ICompoundProperty &arbGeomParams,
+ const PropertyHeader &prop_header,
+ const CDStreamConfig &config,
+ const Alembic::Abc::ISampleSelector &iss)
+{
+ C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr();
+ C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr();
+ bool use_c3f_ptr;
+ bool is_facevarying;
+
+ /* Find the correct interpretation of the data */
+ if (IC3fGeomParam::matches(prop_header)) {
+ IC3fGeomParam color_param(arbGeomParams, prop_header.getName());
+ IC3fGeomParam::Sample sample;
+ BLI_assert(!strcmp("rgb", color_param.getInterpretation()));
+
+ color_param.getIndexed(sample, iss);
+ is_facevarying = sample.getScope() == kFacevaryingScope &&
+ config.totloop == sample.getIndices()->size();
+
+ c3f_ptr = sample.getVals();
+ use_c3f_ptr = true;
+ }
+ else if (IC4fGeomParam::matches(prop_header)) {
+ IC4fGeomParam color_param(arbGeomParams, prop_header.getName());
+ IC4fGeomParam::Sample sample;
+ BLI_assert(!strcmp("rgba", color_param.getInterpretation()));
- void *cd_data = config.add_customdata_cb(config.user_data,
- prop_header.getName().c_str(),
- data_type);
+ color_param.getIndexed(sample, iss);
+ is_facevarying = sample.getScope() == kFacevaryingScope &&
+ config.totloop == sample.getIndices()->size();
- read_mcols(config, cd_data, c3f_ptr, c4f_ptr);
+ c4f_ptr = sample.getVals();
+ use_c3f_ptr = false;
}
- else if (data_type == CD_MLOOPUV) {
- IV2fGeomParam uv_param(prop, prop_header.getName());
- IV2fGeomParam::Sample sample;
- uv_param.getIndexed(sample, iss);
+ else {
+ /* this won't happen due to the checks in read_custom_data() */
+ return;
+ }
+ BLI_assert(c3f_ptr || c4f_ptr);
+
+ /* Read the vertex colors */
+ void *cd_data = config.add_customdata_cb(config.user_data,
+ prop_header.getName().c_str(),
+ CD_MLOOPCOL);
+ MCol *cfaces = static_cast<MCol *>(cd_data);
+ MPoly *mpolys = config.mpoly;
+ MLoop *mloops = config.mloop;
+
+ size_t face_index = 0;
+ size_t color_index;
+ bool bounds_warning_given = false;
- if (uv_param.getScope() != kFacevaryingScope) {
- return;
+ for (int i = 0; i < config.totpoly; ++i) {
+ MPoly *poly = &mpolys[i];
+ MCol *cface = &cfaces[poly->loopstart + poly->totloop];
+ MLoop *mloop = &mloops[poly->loopstart + poly->totloop];
+
+ for (int j = 0; j < poly->totloop; ++j, ++face_index) {
+ --cface;
+ --mloop;
+
+ if (use_c3f_ptr) {
+ color_index = mcols_out_of_bounds_check(
+ is_facevarying ? face_index : mloop->v,
+ c3f_ptr->size(),
+ iobject_full_name, prop_header,
+ bounds_warning_given);
+
+ const Imath::C3f &color = (*c3f_ptr)[color_index];
+ cface->a = FTOCHAR(color[0]);
+ cface->r = FTOCHAR(color[1]);
+ cface->g = FTOCHAR(color[2]);
+ cface->b = 255;
+ }
+ else {
+ color_index = mcols_out_of_bounds_check(
+ is_facevarying ? face_index : mloop->v,
+ c4f_ptr->size(),
+ iobject_full_name, prop_header,
+ bounds_warning_given);
+
+ const Imath::C4f &color = (*c4f_ptr)[color_index];
+ cface->a = FTOCHAR(color[0]);
+ cface->r = FTOCHAR(color[1]);
+ cface->g = FTOCHAR(color[2]);
+ cface->b = FTOCHAR(color[3]);
+ }
}
+ }
+}
+
+static void read_custom_data_uvs(const ICompoundProperty &prop,
+ const PropertyHeader &prop_header,
+ const CDStreamConfig &config,
+ const Alembic::Abc::ISampleSelector &iss)
+{
+ IV2fGeomParam uv_param(prop, prop_header.getName());
+
+ if (!uv_param.isIndexed()) {
+ return;
+ }
- void *cd_data = config.add_customdata_cb(config.user_data,
- prop_header.getName().c_str(),
- data_type);
+ IV2fGeomParam::Sample sample;
+ uv_param.getIndexed(sample, iss);
- read_uvs(config, cd_data, sample.getVals(), sample.getIndices());
+ if (uv_param.getScope() != kFacevaryingScope) {
+ return;
}
+
+ void *cd_data = config.add_customdata_cb(config.user_data,
+ prop_header.getName().c_str(),
+ CD_MLOOPUV);
+
+ read_uvs(config, cd_data, sample.getVals(), sample.getIndices());
}
-void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
+void read_custom_data(const std::string & iobject_full_name,
+ const ICompoundProperty &prop,
+ const CDStreamConfig &config,
+ const Alembic::Abc::ISampleSelector &iss)
{
if (!prop.valid()) {
return;
@@ -362,7 +416,7 @@ void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &confi
continue;
}
- read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPUV);
+ read_custom_data_uvs(prop, prop_header, config, iss);
continue;
}
@@ -372,7 +426,7 @@ void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &confi
continue;
}
- read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPCOL);
+ read_custom_data_mcols(iobject_full_name, prop, prop_header, config, iss);
continue;
}
}
diff --git a/source/blender/alembic/intern/abc_customdata.h b/source/blender/alembic/intern/abc_customdata.h
index bc42e24eba1..b3072a2c9f7 100644
--- a/source/blender/alembic/intern/abc_customdata.h
+++ b/source/blender/alembic/intern/abc_customdata.h
@@ -26,6 +26,7 @@
#define __ABC_CUSTOMDATA_H__
#include <Alembic/Abc/All.h>
+#include <Alembic/AbcGeom/All.h>
struct CustomData;
struct MLoop;
@@ -65,8 +66,8 @@ struct CDStreamConfig {
float weight;
float time;
- int index;
- int ceil_index;
+ Alembic::AbcGeom::index_t index;
+ Alembic::AbcGeom::index_t ceil_index;
CDStreamConfig()
: mloop(NULL)
@@ -95,7 +96,8 @@ void write_custom_data(const OCompoundProperty &prop,
CustomData *data,
int data_type);
-void read_custom_data(const ICompoundProperty &prop,
+void read_custom_data(const std::string & iobject_full_name,
+ const ICompoundProperty &prop,
const CDStreamConfig &config,
const Alembic::Abc::ISampleSelector &iss);
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index d259721e192..4fe65b96f36 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -47,7 +47,7 @@ extern "C" {
#ifdef WIN32
/* needed for MSCV because of snprintf from BLI_string */
-# include "BLI_winstuff.h"
+# include "BLI_winstuff.h"
#endif
#include "BKE_anim.h"
@@ -66,13 +66,14 @@ using Alembic::Abc::OBox3dProperty;
ExportSettings::ExportSettings()
: scene(NULL)
+ , logger()
, selected_only(false)
, visible_layers_only(false)
, renderable_only(false)
, frame_start(1)
, frame_end(1)
- , frame_step_xform(1)
- , frame_step_shape(1)
+ , frame_samples_xform(1)
+ , frame_samples_shape(1)
, shutter_open(0.0)
, shutter_close(1.0)
, global_scale(1.0f)
@@ -82,6 +83,8 @@ ExportSettings::ExportSettings()
, export_vcols(false)
, export_face_sets(false)
, export_vweigths(false)
+ , export_hair(true)
+ , export_particles(true)
, apply_subdiv(false)
, use_subdiv_schema(false)
, export_child_hairs(true)
@@ -105,7 +108,7 @@ static bool object_is_smoke_sim(Object *ob)
return false;
}
-static bool object_is_shape(Object *ob)
+static bool object_type_is_exportable(Object *ob)
{
switch (ob->type) {
case OB_MESH:
@@ -114,6 +117,7 @@ static bool object_is_shape(Object *ob)
}
return true;
+ case OB_EMPTY:
case OB_CURVE:
case OB_SURF:
case OB_CAMERA:
@@ -123,14 +127,31 @@ static bool object_is_shape(Object *ob)
}
}
-static bool export_object(const ExportSettings * const settings, Object *ob)
+
+/**
+ * Returns whether this object should be exported into the Alembic file.
+ *
+ * \param settings: export settings, used for options like 'selected only'.
+ * \param ob: the object in question.
+ * \param is_duplicated: Normally false; true when the object is instanced
+ * into the scene by a dupli-object (e.g. part of a dupligroup).
+ * This ignores selection and layer visibility,
+ * and assumes that the dupli-object itself (e.g. the group-instantiating empty) is exported.
+ */
+static bool export_object(const ExportSettings * const settings, Object *ob,
+ bool is_duplicated)
{
- if (settings->selected_only && !parent_selected(ob)) {
- return false;
- }
+ if (!is_duplicated) {
+ /* These two tests only make sense when the object isn't being instanced
+ * into the scene. When it is, its exportability is determined by
+ * its dupli-object and the DupliObject::no_draw property. */
+ if (settings->selected_only && !parent_selected(ob)) {
+ return false;
+ }
- if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) {
- return false;
+ if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) {
+ return false;
+ }
}
if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) {
@@ -153,11 +174,13 @@ AbcExporter::AbcExporter(Scene *scene, const char *filename, ExportSettings &set
AbcExporter::~AbcExporter()
{
- std::map<std::string, AbcTransformWriter*>::iterator it, e;
- for (it = m_xforms.begin(), e = m_xforms.end(); it != e; ++it) {
- delete it->second;
+ /* Free xforms map */
+ m_xforms_type::iterator it_x, e_x;
+ for (it_x = m_xforms.begin(), e_x = m_xforms.end(); it_x != e_x; ++it_x) {
+ delete it_x->second;
}
+ /* Free shapes vector */
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
delete m_shapes[i];
}
@@ -165,60 +188,56 @@ AbcExporter::~AbcExporter()
delete m_writer;
}
-void AbcExporter::getShutterSamples(double step, bool time_relative,
+void AbcExporter::getShutterSamples(unsigned int nr_of_samples,
+ bool time_relative,
std::vector<double> &samples)
{
+ Scene *scene = m_scene; /* for use in the FPS macro */
samples.clear();
- const double time_factor = time_relative ? m_scene->r.frs_sec : 1.0;
- const double shutter_open = m_settings.shutter_open;
- const double shutter_close = m_settings.shutter_close;
+ unsigned int frame_offset = time_relative ? m_settings.frame_start : 0;
+ double time_factor = time_relative ? FPS : 1.0;
+ double shutter_open = m_settings.shutter_open;
+ double shutter_close = m_settings.shutter_close;
+ double time_inc = (shutter_close - shutter_open) / nr_of_samples;
- /* sample all frame */
- if (shutter_open == 0.0 && shutter_close == 1.0) {
- for (double t = 0; t < 1.0; t += step) {
- samples.push_back((t + m_settings.frame_start) / time_factor);
- }
- }
- else {
- /* sample between shutter open & close */
- const int nsamples = std::max((1.0 / step) - 1.0, 1.0);
- const double time_inc = (shutter_close - shutter_open) / nsamples;
+ /* sample between shutter open & close */
+ for (int sample=0; sample < nr_of_samples; ++sample) {
+ double sample_time = shutter_open + time_inc * sample;
+ double time = (frame_offset + sample_time) / time_factor;
- for (double t = shutter_open; t <= shutter_close; t += time_inc) {
- samples.push_back((t + m_settings.frame_start) / time_factor);
- }
+ samples.push_back(time);
}
}
Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step)
{
- TimeSamplingPtr time_sampling;
std::vector<double> samples;
if (m_settings.frame_start == m_settings.frame_end) {
- time_sampling.reset(new Alembic::Abc::TimeSampling());
- return time_sampling;
+ return TimeSamplingPtr(new Alembic::Abc::TimeSampling());
}
getShutterSamples(step, true, samples);
- Alembic::Abc::TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / m_scene->r.frs_sec);
- time_sampling.reset(new Alembic::Abc::TimeSampling(ts, samples));
+ Alembic::Abc::TimeSamplingType ts(
+ static_cast<uint32_t>(samples.size()),
+ 1.0 / m_scene->r.frs_sec);
- return time_sampling;
+ return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples));
}
-void AbcExporter::getFrameSet(double step, std::set<double> &frames)
+void AbcExporter::getFrameSet(unsigned int nr_of_samples,
+ std::set<double> &frames)
{
frames.clear();
std::vector<double> shutter_samples;
- getShutterSamples(step, false, shutter_samples);
+ getShutterSamples(nr_of_samples, false, shutter_samples);
- for (int frame = m_settings.frame_start; frame <= m_settings.frame_end; ++frame) {
- for (int j = 0, e = shutter_samples.size(); j < e; ++j) {
+ for (double frame = m_settings.frame_start; frame <= m_settings.frame_end; frame += 1.0) {
+ for (size_t j = 0; j < nr_of_samples; ++j) {
frames.insert(frame + shutter_samples[j]);
}
}
@@ -238,9 +257,9 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
}
Scene *scene = m_scene;
- const int fps = FPS;
+ const double fps = FPS;
char buf[16];
- snprintf(buf, 15, "%d", fps);
+ snprintf(buf, 15, "%f", fps);
const std::string str_fps = buf;
Alembic::AbcCoreAbstract::MetaData md;
@@ -250,44 +269,37 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
/* Create time samplings for transforms and shapes. */
- TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_step_xform);
+ TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_samples_xform);
m_trans_sampling_index = m_writer->archive().addTimeSampling(*trans_time);
TimeSamplingPtr shape_time;
- if ((m_settings.frame_step_shape == m_settings.frame_step_xform) ||
+ if ((m_settings.frame_samples_shape == m_settings.frame_samples_xform) ||
(m_settings.frame_start == m_settings.frame_end))
{
shape_time = trans_time;
m_shape_sampling_index = m_trans_sampling_index;
}
else {
- shape_time = createTimeSampling(m_settings.frame_step_shape);
+ shape_time = createTimeSampling(m_settings.frame_samples_shape);
m_shape_sampling_index = m_writer->archive().addTimeSampling(*shape_time);
}
OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index);
- if (m_settings.flatten_hierarchy) {
- createTransformWritersFlat();
- }
- else {
- createTransformWritersHierarchy(bmain->eval_ctx);
- }
-
+ createTransformWritersHierarchy(bmain->eval_ctx);
createShapeWriters(bmain->eval_ctx);
/* Make a list of frames to export. */
std::set<double> xform_frames;
- getFrameSet(m_settings.frame_step_xform, xform_frames);
+ getFrameSet(m_settings.frame_samples_xform, xform_frames);
std::set<double> shape_frames;
- getFrameSet(m_settings.frame_step_shape, shape_frames);
+ getFrameSet(m_settings.frame_samples_shape, shape_frames);
/* Merge all frames needed. */
-
std::set<double> frames(xform_frames);
frames.insert(shape_frames.begin(), shape_frames.end());
@@ -310,7 +322,7 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
const double frame = *begin;
/* 'frame' is offset by start frame, so need to cancel the offset. */
- setCurrentFrame(bmain, frame - m_settings.frame_start);
+ setCurrentFrame(bmain, frame);
if (shape_frames.count(frame) != 0) {
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
@@ -322,7 +334,7 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
continue;
}
- std::map<std::string, AbcTransformWriter *>::iterator xit, xe;
+ m_xforms_type::iterator xit, xe;
for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
xit->second->write();
}
@@ -346,34 +358,16 @@ void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx)
while (base) {
Object *ob = base->object;
- if (export_object(&m_settings, ob)) {
- switch(ob->type) {
- case OB_LAMP:
- case OB_LATTICE:
- case OB_MBALL:
- case OB_SPEAKER:
- /* We do not export transforms for objects of these classes. */
- break;
-
- default:
- exploreTransform(eval_ctx, ob, ob->parent, NULL);
- }
- }
-
- base = base->next;
- }
-}
-
-void AbcExporter::createTransformWritersFlat()
-{
- Base *base = static_cast<Base *>(m_scene->base.first);
+ switch (ob->type) {
+ case OB_LAMP:
+ case OB_LATTICE:
+ case OB_MBALL:
+ case OB_SPEAKER:
+ /* We do not export transforms for objects of these classes. */
+ break;
- while (base) {
- Object *ob = base->object;
-
- if (export_object(&m_settings, ob) && object_is_shape(ob)) {
- std::string name = get_id_name(ob);
- m_xforms[name] = new AbcTransformWriter(ob, m_writer->archive().getTop(), 0, m_trans_sampling_index, m_settings);
+ default:
+ exploreTransform(eval_ctx, ob, ob->parent);
}
base = base->next;
@@ -382,7 +376,15 @@ void AbcExporter::createTransformWritersFlat()
void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent)
{
- createTransformWriter(ob, parent, dupliObParent);
+ /* If an object isn't exported itself, its duplilist shouldn't be
+ * exported either. */
+ if (!export_object(&m_settings, ob, dupliObParent != NULL)) {
+ return;
+ }
+
+ if (object_type_is_exportable(ob)) {
+ createTransformWriter(ob, parent, dupliObParent);
+ }
ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
@@ -391,56 +393,91 @@ void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Obje
Object *dupli_ob = NULL;
Object *dupli_parent = NULL;
- while (link) {
+ for (; link; link = link->next) {
+ /* This skips things like custom bone shapes. */
+ if (m_settings.renderable_only && link->no_draw) {
+ continue;
+ }
+
if (link->type == OB_DUPLIGROUP) {
dupli_ob = link->ob;
dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob;
exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob);
}
-
- link = link->next;
}
}
free_object_duplilist(lb);
}
-void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
+AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
{
- const std::string name = get_object_dag_path_name(ob, dupliObParent);
+ /* An object should not be its own parent, or we'll get infinite loops. */
+ BLI_assert(ob != parent);
+ BLI_assert(ob != dupliObParent);
- /* check if we have already created a transform writer for this object */
- if (m_xforms.find(name) != m_xforms.end()){
- std::cerr << "xform " << name << " already exists\n";
- return;
+ std::string name;
+ if (m_settings.flatten_hierarchy) {
+ name = get_id_name(ob);
+ }
+ else {
+ name = get_object_dag_path_name(ob, dupliObParent);
}
- AbcTransformWriter *parent_xform = NULL;
+ /* check if we have already created a transform writer for this object */
+ AbcTransformWriter *my_writer = getXForm(name);
+ if (my_writer != NULL) {
+ return my_writer;
+ }
- if (parent) {
- const std::string parentname = get_object_dag_path_name(parent, dupliObParent);
- parent_xform = getXForm(parentname);
+ AbcTransformWriter *parent_writer = NULL;
+ Alembic::Abc::OObject alembic_parent;
- if (!parent_xform) {
- if (parent->parent) {
- createTransformWriter(parent, parent->parent, dupliObParent);
+ if (m_settings.flatten_hierarchy || parent == NULL) {
+ /* Parentless objects still have the "top object" as parent
+ * in Alembic. */
+ alembic_parent = m_writer->archive().getTop();
+ }
+ else {
+ /* Since there are so many different ways to find parents (as evident
+ * in the number of conditions below), we can't really look up the
+ * parent by name. We'll just call createTransformWriter(), which will
+ * return the parent's AbcTransformWriter pointer. */
+ if (parent->parent) {
+ if (parent == dupliObParent) {
+ parent_writer = createTransformWriter(parent, parent->parent, NULL);
}
else {
- createTransformWriter(parent, dupliObParent, dupliObParent);
+ parent_writer = createTransformWriter(parent, parent->parent, dupliObParent);
}
-
- parent_xform = getXForm(parentname);
}
- }
+ else if (parent == dupliObParent) {
+ if (dupliObParent->parent == NULL) {
+ parent_writer = createTransformWriter(parent, NULL, NULL);
+ }
+ else {
+ parent_writer = createTransformWriter(parent, dupliObParent->parent, dupliObParent->parent);
+ }
+ }
+ else {
+ parent_writer = createTransformWriter(parent, dupliObParent, dupliObParent);
+ }
- if (parent_xform) {
- m_xforms[name] = new AbcTransformWriter(ob, parent_xform->alembicXform(), parent_xform, m_trans_sampling_index, m_settings);
- m_xforms[name]->setParent(parent);
+ BLI_assert(parent_writer);
+ alembic_parent = parent_writer->alembicXform();
}
- else {
- m_xforms[name] = new AbcTransformWriter(ob, m_writer->archive().getTop(), NULL, m_trans_sampling_index, m_settings);
+
+ my_writer = new AbcTransformWriter(ob, alembic_parent, parent_writer,
+ m_trans_sampling_index, m_settings);
+
+ /* When flattening, the matrix of the dupliobject has to be added. */
+ if (m_settings.flatten_hierarchy && dupliObParent) {
+ my_writer->m_proxy_from = dupliObParent;
}
+
+ m_xforms[name] = my_writer;
+ return my_writer;
}
void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx)
@@ -457,32 +494,60 @@ void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx)
void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent)
{
- ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
-
+ /* If an object isn't exported itself, its duplilist shouldn't be
+ * exported either. */
+ if (!export_object(&m_settings, ob, dupliObParent != NULL)) {
+ return;
+ }
+
createShapeWriter(ob, dupliObParent);
+ ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
+
if (lb) {
- DupliObject *dupliob = static_cast<DupliObject *>(lb->first);
+ DupliObject *link = static_cast<DupliObject *>(lb->first);
- while (dupliob) {
- if (dupliob->type == OB_DUPLIGROUP) {
- exploreObject(eval_ctx, dupliob->ob, ob);
+ for (; link; link = link->next) {
+ /* This skips things like custom bone shapes. */
+ if (m_settings.renderable_only && link->no_draw) {
+ continue;
}
- dupliob = dupliob->next;
+ if (link->type == OB_DUPLIGROUP) {
+ exploreObject(eval_ctx, link->ob, ob);
+ }
}
}
free_object_duplilist(lb);
}
-void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
+void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform)
{
- if (!object_is_shape(ob)) {
+ if (!m_settings.export_hair && !m_settings.export_particles) {
return;
}
- if (!export_object(&m_settings, ob)) {
+ ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first);
+
+ for (; psys; psys = psys->next) {
+ if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) {
+ continue;
+ }
+
+ if (m_settings.export_hair && psys->part->type == PART_HAIR) {
+ m_settings.export_child_hairs = true;
+ m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
+ }
+ else if (m_settings.export_particles && psys->part->type == PART_EMITTER) {
+ m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
+ }
+ }
+}
+
+void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
+{
+ if (!object_type_is_exportable(ob)) {
return;
}
@@ -498,32 +563,18 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
AbcTransformWriter *xform = getXForm(name);
if (!xform) {
- std::cerr << __func__ << ": xform " << name << " is NULL\n";
+ ABC_LOG(m_settings.logger) << __func__ << ": xform " << name << " is NULL\n";
return;
}
- ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first);
-
- for (; psys; psys = psys->next) {
- if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) {
- continue;
- }
+ createParticleSystemsWriters(ob, xform);
- if (psys->part->type == PART_HAIR) {
- m_settings.export_child_hairs = true;
- m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
- }
- else if (psys->part->type == PART_EMITTER) {
- m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
- }
- }
-
- switch(ob->type) {
+ switch (ob->type) {
case OB_MESH:
{
Mesh *me = static_cast<Mesh *>(ob->data);
- if (!me || me->totvert == 0) {
+ if (!me) {
return;
}
@@ -578,7 +629,7 @@ AbcTransformWriter *AbcExporter::getXForm(const std::string &name)
void AbcExporter::setCurrentFrame(Main *bmain, double t)
{
- m_scene->r.cfra = std::floor(t);
- m_scene->r.subframe = t - m_scene->r.cfra;
+ m_scene->r.cfra = static_cast<int>(t);
+ m_scene->r.subframe = static_cast<float>(t) - m_scene->r.cfra;
BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay);
}
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
index b0eb8e185d6..f763922a73b 100644
--- a/source/blender/alembic/intern/abc_exporter.h
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -28,6 +28,8 @@
#include <set>
#include <vector>
+#include "abc_util.h"
+
class AbcObjectWriter;
class AbcTransformWriter;
class ArchiveWriter;
@@ -41,14 +43,15 @@ struct ExportSettings {
ExportSettings();
Scene *scene;
+ SimpleLogger logger;
bool selected_only;
bool visible_layers_only;
bool renderable_only;
double frame_start, frame_end;
- double frame_step_xform;
- double frame_step_shape;
+ double frame_samples_xform;
+ double frame_samples_shape;
double shutter_open;
double shutter_close;
float global_scale;
@@ -60,6 +63,8 @@ struct ExportSettings {
bool export_vcols;
bool export_face_sets;
bool export_vweigths;
+ bool export_hair;
+ bool export_particles;
bool apply_subdiv;
bool use_subdiv_schema;
@@ -86,7 +91,10 @@ class AbcExporter {
ArchiveWriter *m_writer;
- std::map<std::string, AbcTransformWriter *> m_xforms;
+ /* mapping from name to transform writer */
+ typedef std::map<std::string, AbcTransformWriter *> m_xforms_type;
+ m_xforms_type m_xforms;
+
std::vector<AbcObjectWriter *> m_shapes;
public:
@@ -95,20 +103,22 @@ public:
void operator()(Main *bmain, float &progress, bool &was_canceled);
-private:
- void getShutterSamples(double step, bool time_relative, std::vector<double> &samples);
+protected:
+ void getShutterSamples(unsigned int nr_of_samples,
+ bool time_relative,
+ std::vector<double> &samples);
+ void getFrameSet(unsigned int nr_of_samples, std::set<double> &frames);
+private:
Alembic::Abc::TimeSamplingPtr createTimeSampling(double step);
- void getFrameSet(double step, std::set<double> &frames);
-
void createTransformWritersHierarchy(EvaluationContext *eval_ctx);
- void createTransformWritersFlat();
- void createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
+ AbcTransformWriter * createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
void exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent = NULL);
void exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent);
void createShapeWriters(EvaluationContext *eval_ctx);
void createShapeWriter(Object *ob, Object *dupliObParent);
+ void createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform);
AbcTransformWriter *getXForm(const std::string &name);
diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc
index 14bcf6731ea..8f8ed2019d5 100644
--- a/source/blender/alembic/intern/abc_hair.cc
+++ b/source/blender/alembic/intern/abc_hair.cc
@@ -56,6 +56,7 @@ AbcHairWriter::AbcHairWriter(Scene *scene,
ExportSettings &settings,
ParticleSystem *psys)
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+ , m_uv_warning_shown(false)
{
m_psys = psys;
@@ -75,9 +76,8 @@ void AbcHairWriter::do_write()
return;
}
- DerivedMesh *dm = mesh_create_derived_view(m_scene, m_object, CD_MASK_MESH);
+ DerivedMesh *dm = mesh_create_derived_render(m_scene, m_object, CD_MASK_MESH);
DM_ensure_tessface(dm);
- DM_update_tessface_data(dm);
std::vector<Imath::V3f> verts;
std::vector<int32_t> hvertices;
@@ -133,8 +133,10 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
MFace *mface = dm->getTessFaceArray(dm);
MVert *mverts = dm->getVertArray(dm);
- if (!mtface || !mface) {
- std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
+ if ((!mtface || !mface) && !m_uv_warning_shown) {
+ std::fprintf(stderr, "Warning, no UV set found for underlying geometry of %s.\n",
+ m_object->id.name + 2);
+ m_uv_warning_shown = true;
}
ParticleData * pa = m_psys->particles;
@@ -164,7 +166,7 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL, NULL);
- copy_zup_yup(tmp_nor.getValue(), normal);
+ copy_yup_from_zup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
}
}
@@ -198,7 +200,7 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
MVert *mv = mverts + vtx[o];
normal_short_to_float_v3(normal, mv->no);
- copy_zup_yup(tmp_nor.getValue(), normal);
+ copy_yup_from_zup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
found = true;
break;
@@ -239,13 +241,8 @@ void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
invert_m4_m4_safe(inv_mat, m_object->obmat);
MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
- MFace *mface = dm->getTessFaceArray(dm);
MVert *mverts = dm->getVertArray(dm);
- if (!mtface || !mface) {
- std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
- }
-
ParticleCacheKey **cache = m_psys->childcache;
ParticleCacheKey *path;
@@ -254,22 +251,37 @@ void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
path = cache[p];
- if (part->from == PART_FROM_FACE) {
+ if (part->from == PART_FROM_FACE &&
+ part->childtype != PART_CHILD_PARTICLES &&
+ mtface) {
const int num = pc->num;
+ if (num < 0) {
+ ABC_LOG(m_settings.logger)
+ << "Warning, child particle of hair system " << m_psys->name
+ << " has unknown face index of geometry of "<< (m_object->id.name + 2)
+ << ", skipping child hair." << std::endl;
+ continue;
+ }
MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
MTFace *tface = mtface + num;
- if (mface && mtface) {
- float r_uv[2], tmpnor[3], mapfw[4], vec[3];
+ float r_uv[2], tmpnor[3], mapfw[4], vec[3];
- psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
- uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
+ psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
+ uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
- psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL, NULL);
+ psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL, NULL);
- /* Convert Z-up to Y-up. */
- norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
+ /* Convert Z-up to Y-up. */
+ norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
+ }
+ else {
+ if (uv_values.size()) {
+ uv_values.push_back(uv_values[pc->parent]);
+ }
+ if (norm_values.size()) {
+ norm_values.push_back(norm_values[pc->parent]);
}
}
diff --git a/source/blender/alembic/intern/abc_hair.h b/source/blender/alembic/intern/abc_hair.h
index d132b60be12..61f5fe361f8 100644
--- a/source/blender/alembic/intern/abc_hair.h
+++ b/source/blender/alembic/intern/abc_hair.h
@@ -37,6 +37,8 @@ class AbcHairWriter : public AbcObjectWriter {
Alembic::AbcGeom::OCurvesSchema m_schema;
Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
+ bool m_uv_warning_shown;
+
public:
AbcHairWriter(Scene *scene,
Object *ob,
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index 5b282e3c5bb..6545ced8e4a 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -112,7 +112,7 @@ static void get_vertices(DerivedMesh *dm, std::vector<Imath::V3f> &points)
MVert *verts = dm->getVertArray(dm);
for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
- copy_zup_yup(points[i].getValue(), verts[i].co);
+ copy_yup_from_zup(points[i].getValue(), verts[i].co);
}
}
@@ -182,7 +182,7 @@ static void get_vertex_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals
for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
normal_short_to_float_v3(no, verts[i].no);
- copy_zup_yup(normals[i].getValue(), no);
+ copy_yup_from_zup(normals[i].getValue(), no);
}
}
@@ -211,7 +211,7 @@ static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
const int index = ml->v;
- copy_zup_yup(normals[loop_index].getValue(), lnors[index]);
+ copy_yup_from_zup(normals[loop_index].getValue(), lnors[index]);
}
}
}
@@ -226,14 +226,14 @@ static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
BKE_mesh_calc_poly_normal(mp, ml - (mp->totloop - 1), verts, no);
for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
- copy_zup_yup(normals[loop_index].getValue(), no);
+ copy_yup_from_zup(normals[loop_index].getValue(), no);
}
}
else {
/* Smooth shaded, use individual vert normals. */
for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
normal_short_to_float_v3(no, verts[ml->v].no);
- copy_zup_yup(normals[loop_index].getValue(), no);
+ copy_yup_from_zup(normals[loop_index].getValue(), no);
}
}
}
@@ -355,7 +355,7 @@ bool AbcMeshWriter::isAnimated() const
md = md->next;
}
- return false;
+ return me->adt != NULL;
}
void AbcMeshWriter::do_write()
@@ -590,7 +590,7 @@ void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels
float *mesh_vels = reinterpret_cast<float *>(fss->meshVelocities);
for (int i = 0; i < totverts; ++i) {
- copy_zup_yup(vels[i].getValue(), mesh_vels);
+ copy_yup_from_zup(vels[i].getValue(), mesh_vels);
mesh_vels += 3;
}
}
@@ -681,17 +681,17 @@ static void assign_materials(Main *bmain, Object *ob, const std::map<std::string
std::string mat_name = it->first;
mat_iter = mat_map.find(mat_name.c_str());
- Material *assigned_name;
+ Material *assigned_mat;
if (mat_iter == mat_map.end()) {
- assigned_name = BKE_material_add(bmain, mat_name.c_str());
- mat_map[mat_name] = assigned_name;
+ assigned_mat = BKE_material_add(bmain, mat_name.c_str());
+ mat_map[mat_name] = assigned_mat;
}
else {
- assigned_name = mat_iter->second;
+ assigned_mat = mat_iter->second;
}
- assign_material(ob, assigned_name, it->second, BKE_MAT_ASSIGN_OBJECT);
+ assign_material(ob, assigned_mat, it->second, BKE_MAT_ASSIGN_OBDATA);
}
}
}
@@ -726,7 +726,7 @@ static void read_mverts_interp(MVert *mverts, const P3fArraySamplePtr &positions
const Imath::V3f &ceil_pos = (*ceil_positions)[i];
interp_v3_v3v3(tmp, floor_pos.getValue(), ceil_pos.getValue(), weight);
- copy_yup_zup(mvert.co, tmp);
+ copy_zup_from_yup(mvert.co, tmp);
mvert.bweight = 0;
}
@@ -755,7 +755,7 @@ void read_mverts(MVert *mverts, const P3fArraySamplePtr &positions, const N3fArr
MVert &mvert = mverts[i];
Imath::V3f pos_in = (*positions)[i];
- copy_yup_zup(mvert.co, pos_in.getValue());
+ copy_zup_from_yup(mvert.co, pos_in.getValue());
mvert.bweight = 0;
@@ -765,7 +765,7 @@ void read_mverts(MVert *mverts, const P3fArraySamplePtr &positions, const N3fArr
short no[3];
normal_float_to_short_v3(no, nor_in.getValue());
- copy_yup_zup(mvert.no, no);
+ copy_zup_from_yup(mvert.no, no);
}
}
}
@@ -868,53 +868,6 @@ ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
}
}
-/* ************************************************************************** */
-
-AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings)
- : AbcObjectReader(object, settings)
-{
- m_settings->read_flag |= MOD_MESHSEQ_READ_ALL;
-
- IPolyMesh ipoly_mesh(m_iobject, kWrapExisting);
- m_schema = ipoly_mesh.getSchema();
-
- get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
-}
-
-bool AbcMeshReader::valid() const
-{
- return m_schema.valid();
-}
-
-void AbcMeshReader::readObjectData(Main *bmain, float time)
-{
- Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
-
- m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
- m_object->data = mesh;
-
- const ISampleSelector sample_sel(time);
-
- DerivedMesh *dm = CDDM_from_mesh(mesh);
- DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL);
-
- if (ndm != dm) {
- dm->release(dm);
- }
-
- DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
-
- if (m_settings->validate_meshes) {
- BKE_mesh_validate(mesh, false, false);
- }
-
- readFaceSetsSample(bmain, mesh, 0, sample_sel);
-
- if (has_animations(m_schema, m_settings)) {
- addCacheModifier();
- }
-}
-
static bool check_smooth_poly_flag(DerivedMesh *dm)
{
MPoly *mpolys = dm->getPolyArray(dm);
@@ -944,24 +897,96 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type)
{
DerivedMesh *dm = static_cast<DerivedMesh *>(user_data);
CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
- void *cd_ptr = NULL;
-
- if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
- cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name);
-
- if (cd_ptr == NULL) {
- cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm),
- cd_data_type,
- CD_DEFAULT,
- NULL,
- dm->getNumLoops(dm),
- name);
- }
+ void *cd_ptr;
+ CustomData *loopdata;
+ int numloops;
+
+ /* unsupported custom data type -- don't do anything. */
+ if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
+ return NULL;
+ }
+
+ loopdata = dm->getLoopDataLayout(dm);
+ cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name);
+ if (cd_ptr != NULL) {
+ /* layer already exists, so just return it. */
+ return cd_ptr;
+ }
+
+ /* create a new layer, taking care to construct the hopefully-soon-to-be-removed
+ * CD_MTEXPOLY layer too, with the same name. */
+ numloops = dm->getNumLoops(dm);
+ cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT,
+ NULL, numloops, name);
+ if (cd_data_type == CD_MLOOPUV) {
+ CustomData_add_layer_named(dm->getPolyDataLayout(dm),
+ CD_MTEXPOLY, CD_DEFAULT,
+ NULL, numloops, name);
}
return cd_ptr;
}
+static void get_weight_and_index(CDStreamConfig &config,
+ Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling,
+ size_t samples_number)
+{
+ Alembic::AbcGeom::index_t i0, i1;
+
+ config.weight = get_weight_and_index(config.time,
+ time_sampling,
+ samples_number,
+ i0,
+ i1);
+
+ config.index = i0;
+ config.ceil_index = i1;
+}
+
+static void read_mesh_sample(const std::string & iobject_full_name,
+ ImportSettings *settings,
+ const IPolyMeshSchema &schema,
+ const ISampleSelector &selector,
+ CDStreamConfig &config,
+ bool &do_normals)
+{
+ const IPolyMeshSchema::Sample sample = schema.getValue(selector);
+
+ AbcMeshData abc_mesh_data;
+ abc_mesh_data.face_counts = sample.getFaceCounts();
+ abc_mesh_data.face_indices = sample.getFaceIndices();
+ abc_mesh_data.positions = sample.getPositions();
+
+ read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
+
+ do_normals = (abc_mesh_data.face_normals != NULL);
+
+ get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
+
+ if (config.weight != 0.0f) {
+ Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample;
+ schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index));
+ abc_mesh_data.ceil_positions = ceil_sample.getPositions();
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
+ read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
+ read_mverts(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
+ read_mpolys(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
+ read_custom_data(iobject_full_name,
+ schema.getArbGeomParams(), config, selector);
+ }
+}
+
CDStreamConfig get_config(DerivedMesh *dm)
{
CDStreamConfig config;
@@ -978,9 +1003,73 @@ CDStreamConfig get_config(DerivedMesh *dm)
return config;
}
-DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
+/* ************************************************************************** */
+
+AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ m_settings->read_flag |= MOD_MESHSEQ_READ_ALL;
+
+ IPolyMesh ipoly_mesh(m_iobject, kWrapExisting);
+ m_schema = ipoly_mesh.getSchema();
+
+ get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
+}
+
+bool AbcMeshReader::valid() const
+{
+ return m_schema.valid();
+}
+
+void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
+{
+ Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
+
+ m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
+ m_object->data = mesh;
+
+ DerivedMesh *dm = CDDM_from_mesh(mesh);
+ DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
+
+ if (ndm != dm) {
+ dm->release(dm);
+ }
+
+ DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
+
+ if (m_settings->validate_meshes) {
+ BKE_mesh_validate(mesh, false, false);
+ }
+
+ readFaceSetsSample(bmain, mesh, 0, sample_sel);
+
+ if (has_animations(m_schema, m_settings)) {
+ addCacheModifier();
+ }
+}
+
+bool AbcMeshReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::IPolyMesh::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to PolyMesh when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch, Alembic object path points to PolyMesh.";
+ return false;
+ }
+
+ return true;
+}
+
+DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm,
+ const ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str)
{
- ISampleSelector sample_sel(time);
const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel);
const P3fArraySamplePtr &positions = sample.getPositions();
@@ -1003,12 +1092,28 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time,
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
}
+ else {
+ /* If the face count changed (e.g. by triangulation), only read points.
+ * This prevents crash from T49813.
+ * TODO(kevin): perhaps find a better way to do this? */
+ if (face_counts->size() != dm->getNumPolys(dm) ||
+ face_indices->size() != dm->getNumLoops(dm))
+ {
+ settings.read_flag = MOD_MESHSEQ_READ_VERT;
+
+ if (err_str) {
+ *err_str = "Topology has changed, perhaps by triangulating the"
+ " mesh. Only vertices will be read!";
+ }
+ }
+ }
CDStreamConfig config = get_config(new_dm ? new_dm : dm);
- config.time = time;
+ config.time = sample_sel.getRequestedTime();
bool do_normals = false;
- read_mesh_sample(&settings, m_schema, sample_sel, config, do_normals);
+ read_mesh_sample(m_iobject.getFullName(),
+ &settings, m_schema, sample_sel, config, do_normals);
if (new_dm) {
/* Check if we had ME_SMOOTH flag set to restore it. */
@@ -1019,6 +1124,16 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time,
CDDM_calc_normals(new_dm);
CDDM_calc_edges(new_dm);
+ /* Here we assume that the number of materials doesn't change, i.e. that
+ * the material slots that were created when the object was loaded from
+ * Alembic are still valid now. */
+ size_t num_polys = new_dm->getNumPolys(new_dm);
+ if (num_polys > 0) {
+ MPoly *dmpolies = new_dm->getPolyArray(new_dm);
+ std::map<std::string, int> mat_map;
+ assign_facesets_to_mpoly(sample_sel, 0, dmpolies, num_polys, mat_map);
+ }
+
return new_dm;
}
@@ -1029,8 +1144,11 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time,
return dm;
}
-void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
- const ISampleSelector &sample_sel)
+void AbcMeshReader::assign_facesets_to_mpoly(
+ const ISampleSelector &sample_sel,
+ size_t poly_start,
+ MPoly *mpoly, int totpoly,
+ std::map<std::string, int> & r_mat_map)
{
std::vector<std::string> face_sets;
m_schema.getFaceSetNames(face_sets);
@@ -1039,21 +1157,21 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_star
return;
}
- std::map<std::string, int> mat_map;
int current_mat = 0;
for (int i = 0; i < face_sets.size(); ++i) {
const std::string &grp_name = face_sets[i];
- if (mat_map.find(grp_name) == mat_map.end()) {
- mat_map[grp_name] = 1 + current_mat++;
+ if (r_mat_map.find(grp_name) == r_mat_map.end()) {
+ r_mat_map[grp_name] = 1 + current_mat++;
}
- const int assigned_mat = mat_map[grp_name];
+ const int assigned_mat = r_mat_map[grp_name];
const IFaceSet faceset = m_schema.getFaceSet(grp_name);
if (!faceset.valid()) {
+ std::cerr << " Face set " << grp_name << " invalid for " << m_object_name << "\n";
continue;
}
@@ -1065,57 +1183,63 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_star
for (size_t l = 0; l < num_group_faces; l++) {
size_t pos = (*group_faces)[l] + poly_start;
- if (pos >= mesh->totpoly) {
+ if (pos >= totpoly) {
std::cerr << "Faceset overflow on " << faceset.getName() << '\n';
break;
}
- MPoly &poly = mesh->mpoly[pos];
+ MPoly &poly = mpoly[pos];
poly.mat_nr = assigned_mat - 1;
}
}
+}
+
+void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
+ const ISampleSelector &sample_sel)
+{
+ std::map<std::string, int> mat_map;
+ assign_facesets_to_mpoly(sample_sel,
+ poly_start, mesh->mpoly, mesh->totpoly,
+ mat_map);
utils::assign_materials(bmain, m_object, mat_map);
}
-static void get_weight_and_index(CDStreamConfig &config,
- Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling,
- size_t samples_number)
+/* ************************************************************************** */
+
+ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
{
- Alembic::AbcGeom::index_t i0, i1;
+ for (int i = 0, e = totedge; i < e; ++i) {
+ MEdge &edge = edges[i];
- config.weight = get_weight_and_index(config.time,
- time_sampling,
- samples_number,
- i0,
- i1);
+ if (edge.v1 == v1 && edge.v2 == v2) {
+ return &edge;
+ }
+ }
- config.index = i0;
- config.ceil_index = i1;
+ return NULL;
}
-void read_mesh_sample(ImportSettings *settings,
- const IPolyMeshSchema &schema,
- const ISampleSelector &selector,
- CDStreamConfig &config,
- bool &do_normals)
+static void read_subd_sample(const std::string & iobject_full_name,
+ ImportSettings *settings,
+ const ISubDSchema &schema,
+ const ISampleSelector &selector,
+ CDStreamConfig &config)
{
- const IPolyMeshSchema::Sample sample = schema.getValue(selector);
+ const ISubDSchema::Sample sample = schema.getValue(selector);
AbcMeshData abc_mesh_data;
abc_mesh_data.face_counts = sample.getFaceCounts();
abc_mesh_data.face_indices = sample.getFaceIndices();
+ abc_mesh_data.vertex_normals = N3fArraySamplePtr();
+ abc_mesh_data.face_normals = N3fArraySamplePtr();
abc_mesh_data.positions = sample.getPositions();
- read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
-
- do_normals = (abc_mesh_data.face_normals != NULL);
-
get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
if (config.weight != 0.0f) {
- Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample;
- schema.get(ceil_sample, Alembic::Abc::ISampleSelector(static_cast<Alembic::AbcCoreAbstract::index_t>(config.ceil_index)));
+ Alembic::AbcGeom::ISubDSchema::Sample ceil_sample;
+ schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index));
abc_mesh_data.ceil_positions = ceil_sample.getPositions();
}
@@ -1132,27 +1256,13 @@ void read_mesh_sample(ImportSettings *settings,
}
if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
- read_custom_data(schema.getArbGeomParams(), config, selector);
+ read_custom_data(iobject_full_name,
+ schema.getArbGeomParams(), config, selector);
}
-
- /* TODO: face sets */
}
/* ************************************************************************** */
-ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
-{
- for (int i = 0, e = totedge; i < e; ++i) {
- MEdge &edge = edges[i];
-
- if (edge.v1 == v1 && edge.v2 == v2) {
- return &edge;
- }
- }
-
- return NULL;
-}
-
AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
@@ -1169,7 +1279,24 @@ bool AbcSubDReader::valid() const
return m_schema.valid();
}
-void AbcSubDReader::readObjectData(Main *bmain, float time)
+bool AbcSubDReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::ISubD::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to SubD when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch, Alembic object path points to SubD.";
+ return false;
+ }
+
+ return true;
+}
+
+void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
@@ -1177,7 +1304,7 @@ void AbcSubDReader::readObjectData(Main *bmain, float time)
m_object->data = mesh;
DerivedMesh *dm = CDDM_from_mesh(mesh);
- DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL);
+ DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
if (ndm != dm) {
dm->release(dm);
@@ -1185,7 +1312,6 @@ void AbcSubDReader::readObjectData(Main *bmain, float time)
DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
- const ISampleSelector sample_sel(time);
const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
Int32ArraySamplePtr indices = sample.getCreaseIndices();
Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
@@ -1216,50 +1342,11 @@ void AbcSubDReader::readObjectData(Main *bmain, float time)
}
}
-void read_subd_sample(ImportSettings *settings,
- const ISubDSchema &schema,
- const ISampleSelector &selector,
- CDStreamConfig &config)
-{
- const ISubDSchema::Sample sample = schema.getValue(selector);
-
- AbcMeshData abc_mesh_data;
- abc_mesh_data.face_counts = sample.getFaceCounts();
- abc_mesh_data.face_indices = sample.getFaceIndices();
- abc_mesh_data.vertex_normals = N3fArraySamplePtr();
- abc_mesh_data.face_normals = N3fArraySamplePtr();
- abc_mesh_data.positions = sample.getPositions();
-
- get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
-
- if (config.weight != 0.0f) {
- Alembic::AbcGeom::ISubDSchema::Sample ceil_sample;
- schema.get(ceil_sample, Alembic::Abc::ISampleSelector(static_cast<Alembic::AbcCoreAbstract::index_t>(config.ceil_index)));
- abc_mesh_data.ceil_positions = ceil_sample.getPositions();
- }
-
- if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
- read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
- }
-
- if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
- read_mverts(config, abc_mesh_data);
- }
-
- if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
- read_mpolys(config, abc_mesh_data);
- }
-
- if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
- read_custom_data(schema.getArbGeomParams(), config, selector);
- }
-
- /* TODO: face sets */
-}
-
-DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
+DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm,
+ const ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str)
{
- ISampleSelector sample_sel(time);
const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
const P3fArraySamplePtr &positions = sample.getPositions();
@@ -1281,11 +1368,27 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time,
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
}
+ else {
+ /* If the face count changed (e.g. by triangulation), only read points.
+ * This prevents crash from T49813.
+ * TODO(kevin): perhaps find a better way to do this? */
+ if (face_counts->size() != dm->getNumPolys(dm) ||
+ face_indices->size() != dm->getNumLoops(dm))
+ {
+ settings.read_flag = MOD_MESHSEQ_READ_VERT;
+
+ if (err_str) {
+ *err_str = "Topology has changed, perhaps by triangulating the"
+ " mesh. Only vertices will be read!";
+ }
+ }
+ }
/* Only read point data when streaming meshes, unless we need to create new ones. */
CDStreamConfig config = get_config(new_dm ? new_dm : dm);
- config.time = time;
- read_subd_sample(&settings, m_schema, sample_sel, config);
+ config.time = sample_sel.getRequestedTime();
+ read_subd_sample(m_iobject.getFullName(),
+ &settings, m_schema, sample_sel, config);
if (new_dm) {
/* Check if we had ME_SMOOTH flag set to restore it. */
diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h
index 66e6585a3d3..5c1eb01d8e0 100644
--- a/source/blender/alembic/intern/abc_mesh.h
+++ b/source/blender/alembic/intern/abc_mesh.h
@@ -99,21 +99,25 @@ public:
AbcMeshReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const;
+ void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
- void readObjectData(Main *bmain, float time);
-
- DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
+ DerivedMesh *read_derivedmesh(DerivedMesh *dm,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
private:
void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
const Alembic::AbcGeom::ISampleSelector &sample_sel);
-};
-void read_mesh_sample(ImportSettings *settings,
- const Alembic::AbcGeom::IPolyMeshSchema &schema,
- const Alembic::AbcGeom::ISampleSelector &selector,
- CDStreamConfig &config,
- bool &do_normals);
+ void assign_facesets_to_mpoly(const Alembic::Abc::ISampleSelector &sample_sel,
+ size_t poly_start,
+ MPoly *mpoly, int totpoly,
+ std::map<std::string, int> & r_mat_map);
+};
/* ************************************************************************** */
@@ -126,16 +130,16 @@ public:
AbcSubDReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
-
- void readObjectData(Main *bmain, float time);
- DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const;
+ void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
+ DerivedMesh *read_derivedmesh(DerivedMesh *dm,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
};
-void read_subd_sample(ImportSettings *settings,
- const Alembic::AbcGeom::ISubDSchema &schema,
- const Alembic::AbcGeom::ISampleSelector &selector,
- CDStreamConfig &config);
-
/* ************************************************************************** */
void read_mverts(MVert *mverts,
diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc
index 4f57dfdae9e..eaef06fd6d1 100644
--- a/source/blender/alembic/intern/abc_nurbs.cc
+++ b/source/blender/alembic/intern/abc_nurbs.cc
@@ -153,7 +153,7 @@ void AbcNurbsWriter::do_write()
const BPoint *bp = nu->bp;
for (int i = 0; i < size; ++i, ++bp) {
- copy_zup_yup(positions[i].getValue(), bp->vec);
+ copy_yup_from_zup(positions[i].getValue(), bp->vec);
weights[i] = bp->vec[3];
}
@@ -239,7 +239,7 @@ static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
return true;
}
-void AbcNurbsReader::readObjectData(Main *bmain, float time)
+void AbcNurbsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, "abc_curve", OB_SURF));
cu->actvert = CU_ACT_NONE;
@@ -253,7 +253,6 @@ void AbcNurbsReader::readObjectData(Main *bmain, float time)
nu->resolu = cu->resolu;
nu->resolv = cu->resolv;
- const ISampleSelector sample_sel(time);
const INuPatchSchema &schema = it->first;
const INuPatchSchema::Sample smp = schema.getValue(sample_sel);
@@ -281,7 +280,7 @@ void AbcNurbsReader::readObjectData(Main *bmain, float time)
posw_in = (*weights)[i];
}
- copy_yup_zup(bp->vec, pos_in.getValue());
+ copy_zup_from_yup(bp->vec, pos_in.getValue());
bp->vec[3] = posw_in;
bp->f1 = SELECT;
bp->radius = 1.0f;
diff --git a/source/blender/alembic/intern/abc_nurbs.h b/source/blender/alembic/intern/abc_nurbs.h
index 1b2e7a8391f..abe460a8988 100644
--- a/source/blender/alembic/intern/abc_nurbs.h
+++ b/source/blender/alembic/intern/abc_nurbs.h
@@ -54,7 +54,7 @@ public:
bool valid() const;
- void readObjectData(Main *bmain, float time);
+ void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
private:
void getNurbsPatches(const Alembic::Abc::IObject &obj);
diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc
index 314b2568bed..6c4cb60d63c 100644
--- a/source/blender/alembic/intern/abc_object.cc
+++ b/source/blender/alembic/intern/abc_object.cc
@@ -91,20 +91,20 @@ Imath::Box3d AbcObjectWriter::bounds()
if (!bb) {
if (this->m_object->type != OB_CAMERA) {
- std::cerr << "Boundbox is null!\n";
+ ABC_LOG(m_settings.logger) << "Bounding box is null!\n";
}
return Imath::Box3d();
}
- /* Convert Z-up to Y-up. */
+ /* Convert Z-up to Y-up. This also changes which vector goes into which min/max property. */
this->m_bounds.min.x = bb->vec[0][0];
this->m_bounds.min.y = bb->vec[0][2];
- this->m_bounds.min.z = -bb->vec[0][1];
+ this->m_bounds.min.z = -bb->vec[6][1];
this->m_bounds.max.x = bb->vec[6][0];
this->m_bounds.max.y = bb->vec[6][2];
- this->m_bounds.max.z = -bb->vec[6][1];
+ this->m_bounds.max.z = -bb->vec[0][1];
return this->m_bounds;
}
@@ -127,6 +127,7 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings
, m_min_time(std::numeric_limits<chrono_t>::max())
, m_max_time(std::numeric_limits<chrono_t>::min())
, m_refcount(0)
+ , parent_reader(NULL)
{
m_name = object.getFullName();
std::vector<std::string> parts;
@@ -139,6 +140,38 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings
else {
m_object_name = m_data_name = parts[parts.size() - 1];
}
+
+ determine_inherits_xform();
+}
+
+/* Determine whether we can inherit our parent's XForm */
+void AbcObjectReader::determine_inherits_xform()
+{
+ m_inherits_xform = false;
+
+ IXform ixform = xform();
+ if (!ixform) {
+ return;
+ }
+
+ const IXformSchema & schema(ixform.getSchema());
+ if (!schema.valid()) {
+ std::cerr << "Alembic object " << ixform.getFullName()
+ << " has an invalid schema." << std::endl;
+ return;
+ }
+
+ m_inherits_xform = schema.getInheritsXforms();
+
+ IObject ixform_parent = ixform.getParent();
+ if (!ixform_parent.getParent()) {
+ /* The archive top object certainly is not a transform itself, so handle
+ * it as "no parent". */
+ m_inherits_xform = false;
+ }
+ else {
+ m_inherits_xform = ixform_parent && m_inherits_xform;
+ }
}
AbcObjectReader::~AbcObjectReader()
@@ -170,13 +203,13 @@ static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1,
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
- mat0[i][j] = m0[i][j];
+ mat0[i][j] = static_cast<float>(m0[i][j]);
}
}
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
- mat1[i][j] = m1[i][j];
+ mat1[i][j] = static_cast<float>(m1[i][j]);
}
}
@@ -214,7 +247,15 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time)
return s0.getMatrix();
}
-void AbcObjectReader::readObjectMatrix(const float time)
+DerivedMesh *AbcObjectReader::read_derivedmesh(DerivedMesh *dm,
+ const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
+ int UNUSED(read_flag),
+ const char **UNUSED(err_str))
+{
+ return dm;
+}
+
+void AbcObjectReader::setupObjectTransform(const float time)
{
bool is_constant = false;
@@ -236,49 +277,66 @@ void AbcObjectReader::readObjectMatrix(const float time)
}
}
-void AbcObjectReader::read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant)
+Alembic::AbcGeom::IXform AbcObjectReader::xform()
{
- IXform ixform;
- bool has_alembic_parent = false;
-
/* Check that we have an empty object (locator, bone head/tail...). */
if (IXform::matches(m_iobject.getMetaData())) {
- ixform = IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
-
- /* See comment below. */
- has_alembic_parent = m_iobject.getParent().getParent().valid();
+ return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
}
- /* Check that we have an object with actual data. */
- else if (IXform::matches(m_iobject.getParent().getMetaData())) {
- ixform = IXform(m_iobject.getParent(), Alembic::AbcGeom::kWrapExisting);
-
- /* This is a bit hackish, but we need to make sure that extra
- * transformations added to the matrix (rotation/scale) are only applied
- * to root objects. The way objects and their hierarchy are created will
- * need to be revisited at some point but for now this seems to do the
- * trick.
- *
- * Explanation of the trick:
- * The first getParent() will return this object's transformation matrix.
- * The second getParent() will get the parent of the transform, but this
- * might be the archive root ('/') which is valid, so we go passed it to
- * make sure that there is no parent.
- */
- has_alembic_parent = m_iobject.getParent().getParent().getParent().valid();
+
+ /* Check that we have an object with actual data, in which case the
+ * parent Alembic object should contain the transform. */
+ IObject abc_parent = m_iobject.getParent();
+
+ /* The archive's top object can be recognised by not having a parent. */
+ if (abc_parent.getParent()
+ && IXform::matches(abc_parent.getMetaData())) {
+ return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting);
}
+
/* Should not happen. */
- else {
+ std::cerr << "AbcObjectReader::xform(): "
+ << "unable to find IXform for Alembic object '"
+ << m_iobject.getFullName() << "'\n";
+ BLI_assert(false);
+
+ return IXform();
+}
+
+void AbcObjectReader::read_matrix(float r_mat[4][4], const float time,
+ const float scale, bool &is_constant)
+{
+ IXform ixform = xform();
+ if (!ixform) {
return;
}
- const IXformSchema &schema(ixform.getSchema());
-
+ const IXformSchema & schema(ixform.getSchema());
if (!schema.valid()) {
+ std::cerr << "Alembic object " << ixform.getFullName()
+ << " has an invalid schema." << std::endl;
return;
}
const Imath::M44d matrix = get_matrix(schema, time);
- convert_matrix(matrix, m_object, mat, scale, has_alembic_parent);
+ convert_matrix(matrix, m_object, r_mat);
+
+ if (m_inherits_xform) {
+ /* In this case, the matrix in Alembic is in local coordinates, so
+ * convert to world matrix. To prevent us from reading and accumulating
+ * all parent matrices in the Alembic file, we assume that the Blender
+ * parent object is already updated for the current timekey, and use its
+ * world matrix. */
+ BLI_assert(m_object->parent);
+ mul_m4_m4m4(r_mat, m_object->parent->obmat, r_mat);
+ }
+ else {
+ /* Only apply scaling to root objects, parenting will propagate it. */
+ float scale_mat[4][4];
+ scale_m4_fl(scale_mat, scale);
+ scale_mat[3][3] = scale; /* scale translations too */
+ mul_m4_m4m4(r_mat, r_mat, scale_mat);
+ }
is_constant = schema.isConstant();
}
@@ -322,4 +380,5 @@ void AbcObjectReader::incref()
void AbcObjectReader::decref()
{
--m_refcount;
+ BLI_assert(m_refcount >= 0);
}
diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h
index 7ff927b4d33..852ef451f23 100644
--- a/source/blender/alembic/intern/abc_object.h
+++ b/source/blender/alembic/intern/abc_object.h
@@ -76,7 +76,7 @@ private:
/* ************************************************************************** */
-class CacheFile;
+struct CacheFile;
struct ImportSettings {
bool do_convert_mat;
@@ -90,7 +90,7 @@ struct ImportSettings {
/* Length and frame offset of file sequences. */
int sequence_len;
- int offset;
+ int sequence_offset;
/* From MeshSeqCacheModifierData.read_flag */
int read_flag;
@@ -107,7 +107,7 @@ struct ImportSettings {
, is_sequence(false)
, set_frame_range(false)
, sequence_len(1)
- , offset(0)
+ , sequence_offset(0)
, read_flag(0)
, validate_meshes(false)
, cache_file(NULL)
@@ -117,15 +117,7 @@ struct ImportSettings {
template <typename Schema>
static bool has_animations(Schema &schema, ImportSettings *settings)
{
- if (settings->is_sequence) {
- return true;
- }
-
- if (!schema.isConstant()) {
- return true;
- }
-
- return false;
+ return settings->is_sequence || !schema.isConstant();
}
/* ************************************************************************** */
@@ -151,6 +143,11 @@ protected:
* modifiers and/or constraints. */
int m_refcount;
+ bool m_inherits_xform;
+
+public:
+ AbcObjectReader *parent_reader;
+
public:
explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
@@ -158,21 +155,36 @@ public:
const Alembic::Abc::IObject &iobject() const;
+ typedef std::vector<AbcObjectReader *> ptr_vector;
+
+ /**
+ * Returns the transform of this object. This can be the Alembic object
+ * itself (in case of an Empty) or it can be the parent Alembic object.
+ */
+ virtual Alembic::AbcGeom::IXform xform();
+
Object *object() const;
void object(Object *ob);
+ const std::string & name() const { return m_name; }
+ const std::string & object_name() const { return m_object_name; }
+ const std::string & data_name() const { return m_data_name; }
+ bool inherits_xform() const { return m_inherits_xform; }
+
virtual bool valid() const = 0;
+ virtual bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const = 0;
- virtual void readObjectData(Main *bmain, float time) = 0;
+ virtual void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) = 0;
- virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
- {
- (void)time;
- (void)read_flag;
- return dm;
- }
+ virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
- void readObjectMatrix(const float time);
+ /** Reads the object matrix and sets up an object transform if animated. */
+ void setupObjectTransform(const float time);
void addCacheModifier();
@@ -183,7 +195,11 @@ public:
void incref();
void decref();
- void read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant);
+ void read_matrix(float r_mat[4][4], const float time,
+ const float scale, bool &is_constant);
+
+protected:
+ void determine_inherits_xform();
};
Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time);
diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc
index c16da621c77..80567cd6bf0 100644
--- a/source/blender/alembic/intern/abc_points.cc
+++ b/source/blender/alembic/intern/abc_points.cc
@@ -151,12 +151,29 @@ bool AbcPointsReader::valid() const
return m_schema.valid();
}
-void AbcPointsReader::readObjectData(Main *bmain, float time)
+bool AbcPointsReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::IPoints::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to Points when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch, Alembic object path points to Points.";
+ return false;
+ }
+
+ return true;
+}
+
+void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
DerivedMesh *dm = CDDM_from_mesh(mesh);
- DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0);
+ DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, 0, NULL);
if (ndm != dm) {
dm->release(dm);
@@ -178,8 +195,7 @@ void AbcPointsReader::readObjectData(Main *bmain, float time)
void read_points_sample(const IPointsSchema &schema,
const ISampleSelector &selector,
- CDStreamConfig &config,
- float time)
+ CDStreamConfig &config)
{
Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
@@ -189,7 +205,8 @@ void read_points_sample(const IPointsSchema &schema,
N3fArraySamplePtr vnormals;
if (has_property(prop, "N")) {
- const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", time);
+ const Alembic::Util::uint32_t itime = static_cast<Alembic::Util::uint32_t>(selector.getRequestedTime());
+ const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", itime);
if (normals_prop) {
vnormals = normals_prop.getValue(selector);
@@ -199,9 +216,11 @@ void read_points_sample(const IPointsSchema &schema,
read_mverts(config.mvert, positions, vnormals);
}
-DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/)
+DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm,
+ const ISampleSelector &sample_sel,
+ int /*read_flag*/,
+ const char ** /*err_str*/)
{
- ISampleSelector sample_sel(time);
const IPointsSchema::Sample sample = m_schema.getValue(sample_sel);
const P3fArraySamplePtr &positions = sample.getPositions();
@@ -213,7 +232,7 @@ DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time
}
CDStreamConfig config = get_config(new_dm ? new_dm : dm);
- read_points_sample(m_schema, sample_sel, config, time);
+ read_points_sample(m_schema, sample_sel, config);
return new_dm ? new_dm : dm;
}
diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h
index 54873eed346..369a802d763 100644
--- a/source/blender/alembic/intern/abc_points.h
+++ b/source/blender/alembic/intern/abc_points.h
@@ -28,7 +28,7 @@
#include "abc_object.h"
#include "abc_customdata.h"
-class ParticleSystem;
+struct ParticleSystem;
/* ************************************************************************** */
@@ -58,15 +58,20 @@ public:
AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const;
- void readObjectData(Main *bmain, float time);
+ void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
- DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
+ DerivedMesh *read_derivedmesh(DerivedMesh *dm,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
};
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
const Alembic::AbcGeom::ISampleSelector &selector,
- CDStreamConfig &config,
- float time);
+ CDStreamConfig &config);
#endif /* __ABC_POINTS_H__ */
diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc
index 7f8984f9970..5392387663f 100644
--- a/source/blender/alembic/intern/abc_transform.cc
+++ b/source/blender/alembic/intern/abc_transform.cc
@@ -36,6 +36,7 @@ extern "C" {
using Alembic::AbcGeom::OObject;
using Alembic::AbcGeom::OXform;
+using Alembic::Abc::ISampleSelector;
/* ************************************************************************** */
@@ -62,9 +63,9 @@ AbcTransformWriter::AbcTransformWriter(Object *ob,
unsigned int time_sampling,
ExportSettings &settings)
: AbcObjectWriter(NULL, ob, time_sampling, settings, parent)
+ , m_proxy_from(NULL)
{
m_is_animated = hasAnimation(m_object);
- m_parent = NULL;
if (!m_is_animated) {
time_sampling = 0;
@@ -72,6 +73,9 @@ AbcTransformWriter::AbcTransformWriter(Object *ob,
m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling);
m_schema = m_xform.getSchema();
+
+ /* Blender objects can't have a parent without inheriting the transform. */
+ m_inherits_xform = parent != NULL;
}
void AbcTransformWriter::do_write()
@@ -86,28 +90,30 @@ void AbcTransformWriter::do_write()
return;
}
- float mat[4][4];
- create_transform_matrix(m_object, mat);
+ float yup_mat[4][4];
+ create_transform_matrix(m_object, yup_mat,
+ m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD,
+ m_proxy_from);
/* Only apply rotation to root camera, parenting will propagate it. */
- if (m_object->type == OB_CAMERA && !has_parent_camera(m_object)) {
+ if (m_object->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(m_object))) {
float rot_mat[4][4];
- unit_m4(rot_mat);
- rotate_m4(rot_mat, 'X', -M_PI_2);
- mul_m4_m4m4(mat, mat, rot_mat);
+ axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2);
+ mul_m4_m4m4(yup_mat, yup_mat, rot_mat);
}
- if (!m_object->parent) {
+ if (!m_object->parent || !m_inherits_xform) {
/* Only apply scaling to root objects, parenting will propagate it. */
float scale_mat[4][4];
scale_m4_fl(scale_mat, m_settings.global_scale);
- mul_m4_m4m4(mat, mat, scale_mat);
- mul_v3_fl(mat[3], m_settings.global_scale);
+ scale_mat[3][3] = m_settings.global_scale; /* also scale translation */
+ mul_m4_m4m4(yup_mat, yup_mat, scale_mat);
+ yup_mat[3][3] /= m_settings.global_scale; /* normalise the homogeneous component */
}
- m_matrix = convert_matrix(mat);
-
+ m_matrix = convert_matrix(yup_mat);
m_sample.setMatrix(m_matrix);
+ m_sample.setInheritsXforms(m_inherits_xform);
m_schema.set(m_sample);
}
@@ -123,7 +129,7 @@ Imath::Box3d AbcTransformWriter::bounds()
return Imath::transform(bounds, m_matrix);
}
-bool AbcTransformWriter::hasAnimation(Object */*ob*/) const
+bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const
{
/* TODO(kevin): implement this. */
return true;
@@ -134,6 +140,10 @@ bool AbcTransformWriter::hasAnimation(Object */*ob*/) const
AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
+ /* Empties have no data. It makes the import of Alembic files easier to
+ * understand when we name the empty after its name in Alembic. */
+ m_object_name = object.getName();
+
Alembic::AbcGeom::IXform xform(object, Alembic::AbcGeom::kWrapExisting);
m_schema = xform.getSchema();
@@ -145,8 +155,26 @@ bool AbcEmptyReader::valid() const
return m_schema.valid();
}
-void AbcEmptyReader::readObjectData(Main *bmain, float /*time*/)
+bool AbcEmptyReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::IXform::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to XForm when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_EMPTY) {
+ *err_str = "Object type mismatch, Alembic object path points to XForm.";
+ return false;
+ }
+
+ return true;
+}
+
+void AbcEmptyReader::readObjectData(Main *bmain, const ISampleSelector &UNUSED(sample_sel))
{
- m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str());
+ m_object = BKE_object_add_only_object(bmain, OB_EMPTY,
+ m_object_name.c_str());
m_object->data = NULL;
}
diff --git a/source/blender/alembic/intern/abc_transform.h b/source/blender/alembic/intern/abc_transform.h
index 6a3aae216f2..753a4247e9f 100644
--- a/source/blender/alembic/intern/abc_transform.h
+++ b/source/blender/alembic/intern/abc_transform.h
@@ -37,8 +37,11 @@ class AbcTransformWriter : public AbcObjectWriter {
Alembic::Abc::M44d m_matrix;
bool m_is_animated;
- Object *m_parent;
bool m_visible;
+ bool m_inherits_xform;
+
+public:
+ Object *m_proxy_from;
public:
AbcTransformWriter(Object *ob,
@@ -49,7 +52,6 @@ public:
Alembic::AbcGeom::OXform &alembicXform() { return m_xform;}
virtual Imath::Box3d bounds();
- void setParent(Object *p) { m_parent = p; }
private:
virtual void do_write();
@@ -66,8 +68,11 @@ public:
AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const;
- void readObjectData(Main *bmain, float time);
+ void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
};
#endif /* __ABC_TRANSFORM_H__ */
diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc
index f87d18605d4..24a508e8292 100644
--- a/source/blender/alembic/intern/abc_util.cc
+++ b/source/blender/alembic/intern/abc_util.cc
@@ -37,9 +37,11 @@ extern "C" {
#include "DNA_object_types.h"
#include "BLI_math.h"
+
+#include "PIL_time.h"
}
-std::string get_id_name(Object *ob)
+std::string get_id_name(const Object * const ob)
{
if (!ob) {
return "";
@@ -48,7 +50,7 @@ std::string get_id_name(Object *ob)
return get_id_name(&ob->id);
}
-std::string get_id_name(ID *id)
+std::string get_id_name(const ID * const id)
{
std::string name(id->name + 2);
std::replace(name.begin(), name.end(), ' ', '_');
@@ -58,7 +60,7 @@ std::string get_id_name(ID *id)
return name;
}
-std::string get_object_dag_path_name(Object *ob, Object *dupli_parent)
+std::string get_object_dag_path_name(const Object * const ob, Object *dupli_parent)
{
std::string name = get_id_name(ob);
@@ -130,15 +132,28 @@ void split(const std::string &s, const char delim, std::vector<std::string> &tok
}
}
-/* Create a rotation matrix for each axis from euler angles.
- * Euler angles are swaped to change coordinate system. */
-static void create_rotation_matrix(
+void create_swapped_rotation_matrix(
float rot_x_mat[3][3], float rot_y_mat[3][3],
- float rot_z_mat[3][3], const float euler[3], const bool to_yup)
+ float rot_z_mat[3][3], const float euler[3],
+ AbcAxisSwapMode mode)
{
const float rx = euler[0];
- const float ry = (to_yup) ? euler[2] : -euler[2];
- const float rz = (to_yup) ? -euler[1] : euler[1];
+ float ry;
+ float rz;
+
+ /* Apply transformation */
+ switch (mode) {
+ case ABC_ZUP_FROM_YUP:
+ ry = -euler[2];
+ rz = euler[1];
+ break;
+ case ABC_YUP_FROM_ZUP:
+ ry = euler[2];
+ rz = -euler[1];
+ break;
+ default:
+ BLI_assert(false);
+ }
unit_m3(rot_x_mat);
unit_m3(rot_y_mat);
@@ -160,273 +175,109 @@ static void create_rotation_matrix(
rot_z_mat[1][1] = cos(rz);
}
-/* Recompute transform matrix of object in new coordinate system
- * (from Y-Up to Z-Up). */
-void create_transform_matrix(float r_mat[4][4])
+/* Convert matrix from Z=up to Y=up or vice versa. Use yup_mat = zup_mat for in-place conversion. */
+void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode)
{
- float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], transform_mat[4][4];
+ float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4];
float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
- float loc[3], scale[3], euler[3];
+ float src_trans[3], dst_scale[3], src_scale[3], euler[3];
- zero_v3(loc);
- zero_v3(scale);
+ zero_v3(src_trans);
+ zero_v3(dst_scale);
+ zero_v3(src_scale);
zero_v3(euler);
- unit_m3(rot);
- unit_m3(rot_mat);
- unit_m4(scale_mat);
- unit_m4(transform_mat);
- unit_m4(invmat);
+ unit_m3(src_rot);
+ unit_m3(dst_rot);
+ unit_m4(dst_scale_mat);
- /* Compute rotation matrix. */
+ /* We assume there is no sheer component and no homogeneous scaling component. */
+ BLI_assert(fabs(src_mat[0][3]) < 2 * FLT_EPSILON);
+ BLI_assert(fabs(src_mat[1][3]) < 2 * FLT_EPSILON);
+ BLI_assert(fabs(src_mat[2][3]) < 2 * FLT_EPSILON);
+ BLI_assert(fabs(src_mat[3][3] - 1.0f) < 2 * FLT_EPSILON);
- /* Extract location, rotation, and scale from matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, r_mat);
+ /* Extract translation, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat);
/* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
+ mat3_to_eulO(euler, ROT_MODE_XZY, src_rot);
/* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, false);
+ create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, mode);
/* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ mul_m3_m3m3(dst_rot, dst_rot, rot_z_mat);
+ mul_m3_m3m3(dst_rot, dst_rot, rot_y_mat);
+ mul_m3_m3m3(dst_rot, dst_rot, rot_x_mat);
- /* Add rotation matrix to transformation matrix. */
- copy_m4_m3(transform_mat, rot_mat);
+ mat3_to_eulO(euler, ROT_MODE_XZY, dst_rot);
- /* Add translation to transformation matrix. */
- copy_yup_zup(transform_mat[3], loc);
+ /* Start construction of dst_mat from rotation matrix */
+ unit_m4(dst_mat);
+ copy_m4_m3(dst_mat, dst_rot);
- /* Create scale matrix. */
- scale_mat[0][0] = scale[0];
- scale_mat[1][1] = scale[2];
- scale_mat[2][2] = scale[1];
+ /* Apply translation */
+ switch (mode) {
+ case ABC_ZUP_FROM_YUP:
+ copy_zup_from_yup(dst_mat[3], src_trans);
+ break;
+ case ABC_YUP_FROM_ZUP:
+ copy_yup_from_zup(dst_mat[3], src_trans);
+ break;
+ default:
+ BLI_assert(false);
+ }
- /* Add scale to transformation matrix. */
- mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
+ /* Apply scale matrix. Swaps y and z, but does not
+ * negate like translation does. */
+ dst_scale[0] = src_scale[0];
+ dst_scale[1] = src_scale[2];
+ dst_scale[2] = src_scale[1];
- copy_m4_m4(r_mat, transform_mat);
+ size_to_mat4(dst_scale_mat, dst_scale);
+ mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat);
}
-void convert_matrix(const Imath::M44d &xform, Object *ob,
- float r_mat[4][4], float scale, bool has_alembic_parent)
+void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4])
{
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
- r_mat[i][j] = xform[i][j];
+ r_mat[i][j] = static_cast<float>(xform[i][j]);
}
}
if (ob->type == OB_CAMERA) {
float cam_to_yup[4][4];
- unit_m4(cam_to_yup);
- rotate_m4(cam_to_yup, 'X', M_PI_2);
+ axis_angle_to_mat4_single(cam_to_yup, 'X', M_PI_2);
mul_m4_m4m4(r_mat, r_mat, cam_to_yup);
}
- create_transform_matrix(r_mat);
-
- if (ob->parent) {
- mul_m4_m4m4(r_mat, ob->parent->obmat, r_mat);
- }
- /* TODO(kevin) */
- else if (!has_alembic_parent) {
- /* Only apply scaling to root objects, parenting will propagate it. */
- float scale_mat[4][4];
- scale_m4_fl(scale_mat, scale);
- mul_m4_m4m4(r_mat, r_mat, scale_mat);
- mul_v3_fl(r_mat[3], scale);
- }
+ copy_m44_axis_swap(r_mat, r_mat, ABC_ZUP_FROM_YUP);
}
-/* Recompute transform matrix of object in new coordinate system (from Z-Up to Y-Up). */
-void create_transform_matrix(Object *obj, float transform_mat[4][4])
+/* Recompute transform matrix of object in new coordinate system
+ * (from Z-Up to Y-Up). */
+void create_transform_matrix(Object *obj, float r_yup_mat[4][4], AbcMatrixMode mode,
+ Object *proxy_from)
{
- float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], mat[4][4];
- float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
- float loc[3], scale[3], euler[3];
-
- zero_v3(loc);
- zero_v3(scale);
- zero_v3(euler);
- unit_m3(rot);
- unit_m3(rot_mat);
- unit_m4(scale_mat);
- unit_m4(transform_mat);
- unit_m4(invmat);
- unit_m4(mat);
-
- /* get local matrix. */
- if (obj->parent) {
- invert_m4_m4(invmat, obj->parent->obmat);
- mul_m4_m4m4(mat, invmat, obj->obmat);
+ float zup_mat[4][4];
+
+ /* get local or world matrix. */
+ if (mode == ABC_MATRIX_LOCAL && obj->parent) {
+ /* Note that this produces another matrix than the local matrix, due to
+ * constraints and modifiers as well as the obj->parentinv matrix. */
+ invert_m4_m4(obj->parent->imat, obj->parent->obmat);
+ mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat);
}
else {
- copy_m4_m4(mat, obj->obmat);
+ copy_m4_m4(zup_mat, obj->obmat);
}
- /* Compute rotation matrix. */
- switch (obj->rotmode) {
- case ROT_MODE_AXISANGLE:
- {
- /* Get euler angles from axis angle rotation. */
- axis_angle_to_eulO(euler, ROT_MODE_XYZ, obj->rotAxis, obj->rotAngle);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
-
- /* Extract location and scale from matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- break;
- }
- case ROT_MODE_QUAT:
- {
- float q[4];
- copy_v4_v4(q, obj->quat);
-
- /* Swap axis. */
- q[2] = obj->quat[3];
- q[3] = -obj->quat[2];
-
- /* Compute rotation matrix from quaternion. */
- quat_to_mat3(rot_mat, q);
-
- /* Extract location and scale from matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- break;
- }
- case ROT_MODE_XYZ:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
-
- break;
- }
- case ROT_MODE_XZY:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_XZY, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
-
- break;
- }
- case ROT_MODE_YXZ:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_YXZ, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
-
- break;
- }
- case ROT_MODE_YZX:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_YZX, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
-
- break;
- }
- case ROT_MODE_ZXY:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_ZXY, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
-
- break;
- }
- case ROT_MODE_ZYX:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_ZYX, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
-
- break;
- }
+ if (proxy_from) {
+ mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat);
}
- /* Add rotation matrix to transformation matrix. */
- copy_m4_m3(transform_mat, rot_mat);
-
- /* Add translation to transformation matrix. */
- copy_zup_yup(transform_mat[3], loc);
-
- /* Create scale matrix. */
- scale_mat[0][0] = scale[0];
- scale_mat[1][1] = scale[2];
- scale_mat[2][2] = scale[1];
-
- /* Add scale to transformation matrix. */
- mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
+ copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP);
}
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
@@ -519,8 +370,52 @@ AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSe
reader = new AbcCurveReader(object, settings);
}
else {
- assert(false);
+ std::cerr << "Alembic: unknown how to handle objects of schema '"
+ << md.get("schemaObjTitle")
+ << "', skipping object '"
+ << object.getFullName() << "'" << std::endl;
}
return reader;
}
+
+/* ********************** */
+
+ScopeTimer::ScopeTimer(const char *message)
+ : m_message(message)
+ , m_start(PIL_check_seconds_timer())
+{}
+
+ScopeTimer::~ScopeTimer()
+{
+ fprintf(stderr, "%s: %fs\n", m_message, PIL_check_seconds_timer() - m_start);
+}
+
+/* ********************** */
+
+bool SimpleLogger::empty()
+{
+ return ((size_t)m_stream.tellp()) == 0ul;
+}
+
+std::string SimpleLogger::str() const
+{
+ return m_stream.str();
+}
+
+void SimpleLogger::clear()
+{
+ m_stream.clear();
+ m_stream.str("");
+}
+
+std::ostringstream &SimpleLogger::stream()
+{
+ return m_stream;
+}
+
+std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger)
+{
+ os << logger.str();
+ return os;
+}
diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h
index 2f423a9f8c5..2526958111a 100644
--- a/source/blender/alembic/intern/abc_util.h
+++ b/source/blender/alembic/intern/abc_util.h
@@ -32,6 +32,11 @@
# define ABC_INLINE static inline
#endif
+/**
+ * \brief The CacheReader struct is only used for anonymous pointers,
+ * to interface between C and C++ code. This library only creates
+ * pointers to AbcObjectReader (or subclasses thereof).
+ */
struct CacheReader {
int unused;
};
@@ -39,21 +44,26 @@ struct CacheReader {
using Alembic::Abc::chrono_t;
class AbcObjectReader;
-class ImportSettings;
+struct ImportSettings;
struct ID;
struct Object;
-std::string get_id_name(ID *id);
-std::string get_id_name(Object *ob);
-std::string get_object_dag_path_name(Object *ob, Object *dupli_parent);
+std::string get_id_name(const ID * const id);
+std::string get_id_name(const Object * const ob);
+std::string get_object_dag_path_name(const Object * const ob, Object *dupli_parent);
bool object_selected(Object *ob);
bool parent_selected(Object *ob);
Imath::M44d convert_matrix(float mat[4][4]);
-void create_transform_matrix(float r_mat[4][4]);
-void create_transform_matrix(Object *obj, float transform_mat[4][4]);
+
+typedef enum {
+ ABC_MATRIX_WORLD = 1,
+ ABC_MATRIX_LOCAL = 2,
+} AbcMatrixMode;
+void create_transform_matrix(Object *obj, float r_transform_mat[4][4],
+ AbcMatrixMode mode, Object *proxy_from);
void split(const std::string &s, const char delim, std::vector<std::string> &tokens);
@@ -64,8 +74,7 @@ bool begins_with(const TContainer &input, const TContainer &match)
&& std::equal(match.begin(), match.end(), input.begin());
}
-void convert_matrix(const Imath::M44d &xform, Object *ob,
- float r_mat[4][4], float scale, bool has_alembic_parent = false);
+void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4]);
template <typename Schema>
void get_min_max_time_ex(const Schema &schema, chrono_t &min, chrono_t &max)
@@ -116,34 +125,117 @@ AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSe
/* Copy from Y-up to Z-up. */
-ABC_INLINE void copy_yup_zup(float zup[3], const float yup[3])
+ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3])
{
+ const float old_yup1 = yup[1]; /* in case zup == yup */
zup[0] = yup[0];
zup[1] = -yup[2];
- zup[2] = yup[1];
+ zup[2] = old_yup1;
}
-ABC_INLINE void copy_yup_zup(short zup[3], const short yup[3])
+ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3])
{
+ const short old_yup1 = yup[1]; /* in case zup == yup */
zup[0] = yup[0];
zup[1] = -yup[2];
- zup[2] = yup[1];
+ zup[2] = old_yup1;
}
/* Copy from Z-up to Y-up. */
-ABC_INLINE void copy_zup_yup(float yup[3], const float zup[3])
+ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3])
{
+ const float old_zup1 = zup[1]; /* in case yup == zup */
yup[0] = zup[0];
yup[1] = zup[2];
- yup[2] = -zup[1];
+ yup[2] = -old_zup1;
}
-ABC_INLINE void copy_zup_yup(short yup[3], const short zup[3])
+ABC_INLINE void copy_yup_from_zup(short yup[3], const short zup[3])
{
+ const short old_zup1 = zup[1]; /* in case yup == zup */
yup[0] = zup[0];
yup[1] = zup[2];
- yup[2] = -zup[1];
+ yup[2] = -old_zup1;
}
+/* Names are given in (dst, src) order, just like
+ * the parameters of copy_m44_axis_swap() */
+typedef enum {
+ ABC_ZUP_FROM_YUP = 1,
+ ABC_YUP_FROM_ZUP = 2,
+} AbcAxisSwapMode;
+
+/* Create a rotation matrix for each axis from euler angles.
+ * Euler angles are swaped to change coordinate system. */
+void create_swapped_rotation_matrix(
+ float rot_x_mat[3][3], float rot_y_mat[3][3],
+ float rot_z_mat[3][3], const float euler[3],
+ AbcAxisSwapMode mode);
+
+void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode);
+
+/* *************************** */
+
+#undef ABC_DEBUG_TIME
+
+class ScopeTimer {
+ const char *m_message;
+ double m_start;
+
+public:
+ ScopeTimer(const char *message);
+ ~ScopeTimer();
+};
+
+#ifdef ABC_DEBUG_TIME
+# define SCOPE_TIMER(message) ScopeTimer prof(message)
+#else
+# define SCOPE_TIMER(message)
+#endif
+
+/* *************************** */
+
+/**
+ * Utility class whose purpose is to more easily log related informations. An
+ * instance of the SimpleLogger can be created in any context, and will hold a
+ * copy of all the strings passed to its output stream.
+ *
+ * Different instances of the class may be accessed from different threads,
+ * although accessing the same instance from different threads will lead to race
+ * conditions.
+ */
+class SimpleLogger {
+ std::ostringstream m_stream;
+
+public:
+ /**
+ * Check whether or not the SimpleLogger's stream is empty.
+ */
+ bool empty();
+
+ /**
+ * Return a copy of the string contained in the SimpleLogger's stream.
+ */
+ std::string str() const;
+
+ /**
+ * Remove the bits set on the SimpleLogger's stream and clear its string.
+ */
+ void clear();
+
+ /**
+ * Return a reference to the SimpleLogger's stream, in order to e.g. push
+ * content into it.
+ */
+ std::ostringstream &stream();
+};
+
+#define ABC_LOG(logger) logger.stream()
+
+/**
+ * Pass the content of the logger's stream to the specified std::ostream.
+ */
+std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger);
+
#endif /* __ABC_UTIL_H__ */
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index e690a255505..5503dcb1527 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -21,6 +21,7 @@
*/
#include "../ABC_alembic.h"
+#include <boost/foreach.hpp>
#include <Alembic/AbcMaterial/IMaterial.h>
@@ -120,91 +121,62 @@ ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive)
/* NOTE: this function is similar to visit_objects below, need to keep them in
* sync. */
-static void gather_objects_paths(const IObject &object, ListBase *object_paths)
+static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
{
if (!object.valid()) {
- return;
+ return false;
}
- for (int i = 0; i < object.getNumChildren(); ++i) {
- IObject child = object.getChild(i);
- if (!child.valid()) {
- continue;
- }
+ size_t children_claiming_this_object = 0;
+ size_t num_children = object.getNumChildren();
- bool get_path = false;
+ for (size_t i = 0; i < num_children; ++i) {
+ bool child_claims_this_object = gather_objects_paths(object.getChild(i), object_paths);
+ children_claiming_this_object += child_claims_this_object ? 1 : 0;
+ }
- const MetaData &md = child.getMetaData();
+ const MetaData &md = object.getMetaData();
+ bool get_path = false;
+ bool parent_is_part_of_this_object = false;
- if (IXform::matches(md)) {
- /* Check whether or not this object is a Maya locator, which is
- * similar to empties used as parent object in Blender. */
- if (has_property(child.getProperties(), "locator")) {
- get_path = true;
- }
- else {
- /* Avoid creating an empty object if the child of this transform
- * is not a transform (that is an empty). */
- if (child.getNumChildren() == 1) {
- if (IXform::matches(child.getChild(0).getMetaData())) {
- get_path = true;
- }
-#if 0
- else {
- std::cerr << "Skipping " << child.getFullName() << '\n';
- }
-#endif
- }
- else {
- get_path = true;
- }
- }
- }
- else if (IPolyMesh::matches(md)) {
- get_path = true;
- }
- else if (ISubD::matches(md)) {
- get_path = true;
- }
- else if (INuPatch::matches(md)) {
-#ifdef USE_NURBS
- get_path = true;
-#endif
- }
- else if (ICamera::matches(md)) {
- get_path = true;
- }
- else if (IPoints::matches(md)) {
- get_path = true;
- }
- else if (IMaterial::matches(md)) {
- /* Pass for now. */
- }
- else if (ILight::matches(md)) {
- /* Pass for now. */
- }
- else if (IFaceSet::matches(md)) {
- /* Pass, those are handled in the mesh reader. */
- }
- else if (ICurves::matches(md)) {
+ if (!object.getParent()) {
+ /* The root itself is not an object we should import. */
+ }
+ else if (IXform::matches(md)) {
+ if (has_property(object.getProperties(), "locator")) {
get_path = true;
}
else {
- assert(false);
+ get_path = children_claiming_this_object == 0;
}
- if (get_path) {
- AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
- MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
-
- BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
+ /* Transforms are never "data" for their parent. */
+ parent_is_part_of_this_object = false;
+ }
+ else {
+ /* These types are "data" for their parent. */
+ get_path =
+ IPolyMesh::matches(md) ||
+ ISubD::matches(md) ||
+#ifdef USE_NURBS
+ INuPatch::matches(md) ||
+#endif
+ ICamera::matches(md) ||
+ IPoints::matches(md) ||
+ ICurves::matches(md);
+ parent_is_part_of_this_object = get_path;
+ }
- BLI_addtail(object_paths, abc_path);
- }
+ if (get_path) {
+ void *abc_path_void = MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath");
+ AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(abc_path_void);
- gather_objects_paths(child, object_paths);
+ BLI_strncpy(abc_path->path, object.getFullName().c_str(), sizeof(abc_path->path));
+ BLI_addtail(object_paths, abc_path);
}
+
+ return parent_is_part_of_this_object;
}
AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths)
@@ -266,6 +238,7 @@ struct ExportJobData {
float *progress;
bool was_canceled;
+ bool export_ok;
};
static void export_startjob(void *customdata, short *stop, short *do_update, float *progress)
@@ -299,12 +272,14 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
BKE_scene_update_for_newframe(data->bmain->eval_ctx, data->bmain,
scene, scene->lay);
}
+
+ data->export_ok = !data->was_canceled;
}
catch (const std::exception &e) {
- std::cerr << "Abc Export error: " << e.what() << '\n';
+ ABC_LOG(data->settings.logger) << "Abc Export error: " << e.what() << '\n';
}
catch (...) {
- std::cerr << "Abc Export error\n";
+ ABC_LOG(data->settings.logger) << "Abc Export: unknown error...\n";
}
}
@@ -316,26 +291,49 @@ static void export_endjob(void *customdata)
BLI_delete(data->filename, false, false);
}
+ if (!data->settings.logger.empty()) {
+ std::cerr << data->settings.logger;
+ WM_report(RPT_ERROR, "Errors occured during the export, look in the console to know more...");
+ }
+
G.is_rendering = false;
BKE_spacedata_draw_locks(false);
}
-void ABC_export(
+bool ABC_export(
Scene *scene,
bContext *C,
const char *filepath,
- const struct AlembicExportParams *params)
+ const struct AlembicExportParams *params,
+ bool as_background_job)
{
ExportJobData *job = static_cast<ExportJobData *>(MEM_mallocN(sizeof(ExportJobData), "ExportJobData"));
job->scene = scene;
job->bmain = CTX_data_main(C);
+ job->export_ok = false;
BLI_strncpy(job->filename, filepath, 1024);
+ /* Alright, alright, alright....
+ *
+ * ExportJobData contains an ExportSettings containing a SimpleLogger.
+ *
+ * Since ExportJobData is a C-style struct dynamically allocated with
+ * MEM_mallocN (see above), its construtor is never called, therefore the
+ * ExportSettings constructor is not called which implies that the
+ * SimpleLogger one is not called either. SimpleLogger in turn does not call
+ * the constructor of its data members which ultimately means that its
+ * std::ostringstream member has a NULL pointer. To be able to properly use
+ * the stream's operator<<, the pointer needs to be set, therefore we have
+ * to properly construct everything. And this is done using the placement
+ * new operator as here below. It seems hackish, but I'm too lazy to
+ * do bigger refactor and maybe there is a better way which does not involve
+ * hardcore refactoring. */
+ new (&job->settings) ExportSettings();
job->settings.scene = job->scene;
job->settings.frame_start = params->frame_start;
job->settings.frame_end = params->frame_end;
- job->settings.frame_step_xform = params->frame_step_xform;
- job->settings.frame_step_shape = params->frame_step_shape;
+ job->settings.frame_samples_xform = params->frame_samples_xform;
+ job->settings.frame_samples_shape = params->frame_samples_shape;
job->settings.shutter_open = params->shutter_open;
job->settings.shutter_close = params->shutter_close;
job->settings.selected_only = params->selected_only;
@@ -343,6 +341,8 @@ void ABC_export(
job->settings.export_normals = params->normals;
job->settings.export_uvs = params->uvs;
job->settings.export_vcols = params->vcolors;
+ job->settings.export_hair = params->export_hair;
+ job->settings.export_particles = params->export_particles;
job->settings.apply_subdiv = params->apply_subdiv;
job->settings.flatten_hierarchy = params->flatten_hierarchy;
job->settings.visible_layers_only = params->visible_layers_only;
@@ -359,136 +359,248 @@ void ABC_export(
std::swap(job->settings.frame_start, job->settings.frame_end);
}
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- job->scene,
- "Alembic Export",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_ALEMBIC);
+ bool export_ok = false;
+ if (as_background_job) {
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ job->scene,
+ "Alembic Export",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_ALEMBIC);
- /* setup job */
- WM_jobs_customdata_set(wm_job, job, MEM_freeN);
- WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
- WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob);
+ /* setup job */
+ WM_jobs_customdata_set(wm_job, job, MEM_freeN);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
+ WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob);
- WM_jobs_start(CTX_wm_manager(C), wm_job);
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
+ else {
+ /* Fake a job context, so that we don't need NULL pointer checks while exporting. */
+ short stop = 0, do_update = 0;
+ float progress = 0.f;
+
+ export_startjob(job, &stop, &do_update, &progress);
+ export_endjob(job);
+ export_ok = job->export_ok;
+
+ MEM_freeN(job);
+ }
+
+ return export_ok;
}
/* ********************** Import file ********************** */
-static void visit_object(const IObject &object,
- std::vector<AbcObjectReader *> &readers,
- GHash *parent_map,
- ImportSettings &settings)
+/**
+ * Generates an AbcObjectReader for this Alembic object and its children.
+ *
+ * \param object The Alembic IObject to visit.
+ * \param readers The created AbcObjectReader * will be appended to this vector.
+ * \param settings Import settings, not used directly but passed to the
+ * AbcObjectReader subclass constructors.
+ * \param r_assign_as_parent Return parameter, contains a list of reader
+ * pointers, whose parent pointer should still be set.
+ * This is filled when this call to visit_object() didn't create
+ * a reader that should be the parent.
+ * \return A pair of boolean and reader pointer. The boolean indicates whether
+ * this IObject claims its parent as part of the same object
+ * (for example an IPolyMesh object would claim its parent, as the mesh
+ * is interpreted as the object's data, and the parent IXform as its
+ * Blender object). The pointer is the AbcObjectReader that represents
+ * the IObject parameter.
+ *
+ * NOTE: this function is similar to gather_object_paths above, need to keep
+ * them in sync. */
+static std::pair<bool, AbcObjectReader *> visit_object(
+ const IObject &object,
+ AbcObjectReader::ptr_vector &readers,
+ ImportSettings &settings,
+ AbcObjectReader::ptr_vector &r_assign_as_parent)
{
+ const std::string & full_name = object.getFullName();
+
if (!object.valid()) {
- return;
+ std::cerr << " - "
+ << full_name
+ << ": object is invalid, skipping it and all its children.\n";
+ return std::make_pair(false, static_cast<AbcObjectReader *>(NULL));
}
- for (int i = 0; i < object.getNumChildren(); ++i) {
- IObject child = object.getChild(i);
-
- if (!child.valid()) {
- continue;
- }
-
- AbcObjectReader *reader = NULL;
+ /* The interpretation of data by the children determine the role of this
+ * object. This is especially important for Xform objects, as they can be
+ * either part of a Blender object or a Blender object (Empty) themselves.
+ */
+ size_t children_claiming_this_object = 0;
+ size_t num_children = object.getNumChildren();
+ AbcObjectReader::ptr_vector claiming_child_readers;
+ AbcObjectReader::ptr_vector nonclaiming_child_readers;
+ AbcObjectReader::ptr_vector assign_as_parent;
+ for (size_t i = 0; i < num_children; ++i) {
+ const IObject ichild = object.getChild(i);
- const MetaData &md = child.getMetaData();
+ /* TODO: When we only support C++11, use std::tie() instead. */
+ std::pair<bool, AbcObjectReader *> child_result;
+ child_result = visit_object(ichild, readers, settings, assign_as_parent);
- if (IXform::matches(md)) {
- bool create_xform = false;
+ bool child_claims_this_object = child_result.first;
+ AbcObjectReader *child_reader = child_result.second;
- /* Check whether or not this object is a Maya locator, which is
- * similar to empties used as parent object in Blender. */
- if (has_property(child.getProperties(), "locator")) {
- create_xform = true;
+ if (child_reader == NULL) {
+ BLI_assert(!child_claims_this_object);
+ }
+ else {
+ if (child_claims_this_object) {
+ claiming_child_readers.push_back(child_reader);
}
else {
- /* Avoid creating an empty object if the child of this transform
- * is not a transform (that is an empty). */
- if (child.getNumChildren() == 1) {
- if (IXform::matches(child.getChild(0).getMetaData())) {
- create_xform = true;
- }
-#if 0
- else {
- std::cerr << "Skipping " << child.getFullName() << '\n';
- }
-#endif
- }
- else {
- create_xform = true;
- }
+ nonclaiming_child_readers.push_back(child_reader);
}
+ }
- if (create_xform) {
- reader = new AbcEmptyReader(child, settings);
- }
+ children_claiming_this_object += child_claims_this_object ? 1 : 0;
+ }
+ BLI_assert(children_claiming_this_object == claiming_child_readers.size());
+
+ AbcObjectReader *reader = NULL;
+ const MetaData &md = object.getMetaData();
+ bool parent_is_part_of_this_object = false;
+
+ if (!object.getParent()) {
+ /* The root itself is not an object we should import. */
+ }
+ else if (IXform::matches(md)) {
+ bool create_empty;
+
+ /* An xform can either be a Blender Object (if it contains a mesh, for
+ * example), but it can also be an Empty. Its correct translation to
+ * Blender's data model depends on its children. */
+
+ /* Check whether or not this object is a Maya locator, which is
+ * similar to empties used as parent object in Blender. */
+ if (has_property(object.getProperties(), "locator")) {
+ create_empty = true;
}
- else if (IPolyMesh::matches(md)) {
- reader = new AbcMeshReader(child, settings);
+ else {
+ create_empty = claiming_child_readers.empty();
}
- else if (ISubD::matches(md)) {
- reader = new AbcSubDReader(child, settings);
+
+ if (create_empty) {
+ reader = new AbcEmptyReader(object, settings);
}
- else if (INuPatch::matches(md)) {
+ }
+ else if (IPolyMesh::matches(md)) {
+ reader = new AbcMeshReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (ISubD::matches(md)) {
+ reader = new AbcSubDReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (INuPatch::matches(md)) {
#ifdef USE_NURBS
- /* TODO(kevin): importing cyclic NURBS from other software crashes
- * at the moment. This is due to the fact that NURBS in other
- * software have duplicated points which causes buffer overflows in
- * Blender. Need to figure out exactly how these points are
- * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
- * Until this is fixed, disabling NURBS reading. */
- reader = new AbcNurbsReader(child, settings);
+ /* TODO(kevin): importing cyclic NURBS from other software crashes
+ * at the moment. This is due to the fact that NURBS in other
+ * software have duplicated points which causes buffer overflows in
+ * Blender. Need to figure out exactly how these points are
+ * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
+ * Until this is fixed, disabling NURBS reading. */
+ reader = new AbcNurbsReader(object, settings);
+ parent_is_part_of_this_object = true;
#endif
+ }
+ else if (ICamera::matches(md)) {
+ reader = new AbcCameraReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (IPoints::matches(md)) {
+ reader = new AbcPointsReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (IMaterial::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (ILight::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (IFaceSet::matches(md)) {
+ /* Pass, those are handled in the mesh reader. */
+ }
+ else if (ICurves::matches(md)) {
+ reader = new AbcCurveReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else {
+ std::cerr << "Alembic object " << full_name
+ << " is of unsupported schema type '"
+ << object.getMetaData().get("schemaObjTitle") << "'"
+ << std::endl;
+ }
+
+ if (reader) {
+ /* We have created a reader, which should imply that this object is
+ * not claimed as part of any child Alembic object. */
+ BLI_assert(claiming_child_readers.empty());
+
+ readers.push_back(reader);
+ reader->incref();
+
+ AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
+ MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
+ BLI_strncpy(abc_path->path, full_name.c_str(), sizeof(abc_path->path));
+ BLI_addtail(&settings.cache_file->object_paths, abc_path);
+
+ /* We can now assign this reader as parent for our children. */
+ if (nonclaiming_child_readers.size() + assign_as_parent.size() > 0) {
+ /* TODO: When we only support C++11, use for (a: b) instead. */
+ BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) {
+ child_reader->parent_reader = reader;
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) {
+ child_reader->parent_reader = reader;
+ }
}
- else if (ICamera::matches(md)) {
- reader = new AbcCameraReader(child, settings);
- }
- else if (IPoints::matches(md)) {
- reader = new AbcPointsReader(child, settings);
- }
- else if (IMaterial::matches(md)) {
- /* Pass for now. */
- }
- else if (ILight::matches(md)) {
- /* Pass for now. */
- }
- else if (IFaceSet::matches(md)) {
- /* Pass, those are handled in the mesh reader. */
- }
- else if (ICurves::matches(md)) {
- reader = new AbcCurveReader(child, settings);
+ }
+ else if (object.getParent()) {
+ if (claiming_child_readers.size() > 0) {
+ /* The first claiming child will serve just fine as parent to
+ * our non-claiming children. Since all claiming children share
+ * the same XForm, it doesn't really matter which one we pick. */
+ AbcObjectReader *claiming_child = claiming_child_readers[0];
+ BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) {
+ child_reader->parent_reader = claiming_child;
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) {
+ child_reader->parent_reader = claiming_child;
+ }
+ /* Claiming children should have our parent set as their parent. */
+ BOOST_FOREACH(AbcObjectReader *child_reader, claiming_child_readers) {
+ r_assign_as_parent.push_back(child_reader);
+ }
}
else {
- assert(false);
- }
-
- if (reader) {
- readers.push_back(reader);
- reader->incref();
-
- AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
- MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
-
- BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
-
- BLI_addtail(&settings.cache_file->object_paths, abc_path);
-
- /* Cast to `void *` explicitly to avoid compiler errors because it
- * is a `const char *` which the compiler cast to `const void *`
- * instead of the expected `void *`. */
- BLI_ghash_insert(parent_map, (void *)child.getFullName().c_str(), reader);
+ /* This object isn't claimed by any child, and didn't produce
+ * a reader. Odd situation, could be the top Alembic object, or
+ * an unsupported Alembic schema. Delegate to our parent. */
+ BOOST_FOREACH(AbcObjectReader *child_reader, claiming_child_readers) {
+ r_assign_as_parent.push_back(child_reader);
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) {
+ r_assign_as_parent.push_back(child_reader);
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) {
+ r_assign_as_parent.push_back(child_reader);
+ }
}
-
- visit_object(child, readers, parent_map, settings);
}
+
+ return std::make_pair(parent_is_part_of_this_object, reader);
}
enum {
ABC_NO_ERROR = 0,
ABC_ARCHIVE_FAIL,
+ ABC_UNSUPPORTED_HDF5,
};
struct ImportJobData {
@@ -498,7 +610,6 @@ struct ImportJobData {
char filename[1024];
ImportSettings settings;
- GHash *parent_map;
std::vector<AbcObjectReader *> readers;
short *stop;
@@ -507,6 +618,7 @@ struct ImportJobData {
char error_code;
bool was_cancelled;
+ bool import_ok;
};
ABC_INLINE bool is_mesh_and_strands(const IObject &object)
@@ -542,6 +654,8 @@ ABC_INLINE bool is_mesh_and_strands(const IObject &object)
static void import_startjob(void *user_data, short *stop, short *do_update, float *progress)
{
+ SCOPE_TIMER("Alembic import, objects reading and creation");
+
ImportJobData *data = static_cast<ImportJobData *>(user_data);
data->stop = stop;
@@ -551,8 +665,12 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
ArchiveReader *archive = new ArchiveReader(data->filename);
if (!archive->valid()) {
- delete archive;
+#ifndef WITH_ALEMBIC_HDF5
+ data->error_code = archive->is_hdf5() ? ABC_UNSUPPORTED_HDF5 : ABC_ARCHIVE_FAIL;
+#else
data->error_code = ABC_ARCHIVE_FAIL;
+#endif
+ delete archive;
return;
}
@@ -573,11 +691,12 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
*data->do_update = true;
*data->progress = 0.05f;
- data->parent_map = BLI_ghash_str_new("alembic parent ghash");
-
/* Parse Alembic Archive. */
+ AbcObjectReader::ptr_vector assign_as_parent;
+ visit_object(archive->getTop(), data->readers, data->settings, assign_as_parent);
- visit_object(archive->getTop(), data->readers, data->parent_map, data->settings);
+ /* There shouldn't be any orphans. */
+ BLI_assert(assign_as_parent.size() == 0);
if (G.is_break) {
data->was_cancelled = true;
@@ -595,19 +714,23 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
chrono_t min_time = std::numeric_limits<chrono_t>::max();
chrono_t max_time = std::numeric_limits<chrono_t>::min();
+ ISampleSelector sample_sel(0.0f);
std::vector<AbcObjectReader *>::iterator iter;
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
AbcObjectReader *reader = *iter;
if (reader->valid()) {
- reader->readObjectData(data->bmain, 0.0f);
- reader->readObjectMatrix(0.0f);
+ reader->readObjectData(data->bmain, sample_sel);
min_time = std::min(min_time, reader->minTime());
max_time = std::max(max_time, reader->maxTime());
}
+ else {
+ std::cerr << "Object " << reader->name() << " in Alembic file "
+ << data->filename << " is invalid.\n";
+ }
- *data->progress = 0.1f + 0.6f * (++i / size);
+ *data->progress = 0.1f + 0.3f * (++i / size);
*data->do_update = true;
if (G.is_break) {
@@ -620,50 +743,36 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
Scene *scene = data->scene;
if (data->settings.is_sequence) {
- SFRA = data->settings.offset;
+ SFRA = data->settings.sequence_offset;
EFRA = SFRA + (data->settings.sequence_len - 1);
CFRA = SFRA;
}
else if (min_time < max_time) {
- SFRA = min_time * FPS;
- EFRA = max_time * FPS;
+ SFRA = static_cast<int>(round(min_time * FPS));
+ EFRA = static_cast<int>(round(max_time * FPS));
CFRA = SFRA;
}
}
- /* Setup parentship. */
-
- i = 0;
+ /* Setup parenthood. */
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
const AbcObjectReader *reader = *iter;
- const AbcObjectReader *parent_reader = NULL;
- const IObject &iobject = reader->iobject();
-
- IObject parent = iobject.getParent();
-
- if (!IXform::matches(iobject.getHeader())) {
- /* In the case of an non XForm node, the parent is the transform
- * matrix of the data itself, so we get the its grand parent.
- */
+ const AbcObjectReader *parent_reader = reader->parent_reader;
+ Object *ob = reader->object();
- /* Special case with object only containing a mesh and some strands,
- * we want both objects to be parented to the same object. */
- if (!is_mesh_and_strands(parent)) {
- parent = parent.getParent();
- }
+ if (parent_reader == NULL || !reader->inherits_xform()) {
+ ob->parent = NULL;
}
-
- parent_reader = reinterpret_cast<AbcObjectReader *>(
- BLI_ghash_lookup(data->parent_map, parent.getFullName().c_str()));
-
- if (parent_reader) {
- Object *parent = parent_reader->object();
-
- if (parent != NULL && reader->object() != parent) {
- Object *ob = reader->object();
- ob->parent = parent;
- }
+ else {
+ ob->parent = parent_reader->object();
}
+ }
+
+ /* Setup transformations and constraints. */
+ i = 0;
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ AbcObjectReader *reader = *iter;
+ reader->setupObjectTransform(0.0f);
*data->progress = 0.7f + 0.3f * (++i / size);
*data->do_update = true;
@@ -677,6 +786,8 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
static void import_endjob(void *user_data)
{
+ SCOPE_TIMER("Alembic import, cleanup");
+
ImportJobData *data = static_cast<ImportJobData *>(user_data);
std::vector<AbcObjectReader *>::iterator iter;
@@ -686,23 +797,25 @@ static void import_endjob(void *user_data)
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
Object *ob = (*iter)->object();
- if (ob->data) {
- BKE_libblock_free_us(data->bmain, ob->data);
- ob->data = NULL;
- }
+ /* It's possible that cancellation occured between the creation of
+ * the reader and the creation of the Blender object. */
+ if (ob == NULL) continue;
BKE_libblock_free_us(data->bmain, ob);
}
}
else {
/* Add object to scene. */
+ Base *base;
+
BKE_scene_base_deselect_all(data->scene);
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
Object *ob = (*iter)->object();
ob->lay = data->scene->lay;
- BKE_scene_base_add(data->scene, ob);
+ base = BKE_scene_base_add(data->scene, ob);
+ BKE_scene_base_select(data->scene, base);
DAG_id_tag_update_ex(data->bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
@@ -719,17 +832,17 @@ static void import_endjob(void *user_data)
}
}
- if (data->parent_map) {
- BLI_ghash_free(data->parent_map, NULL, NULL);
- }
-
switch (data->error_code) {
default:
case ABC_NO_ERROR:
+ data->import_ok = !data->was_cancelled;
break;
case ABC_ARCHIVE_FAIL:
WM_report(RPT_ERROR, "Could not open Alembic archive for reading! See console for detail.");
break;
+ case ABC_UNSUPPORTED_HDF5:
+ WM_report(RPT_ERROR, "Alembic archive in obsolete HDF5 format is not supported.");
+ break;
}
WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene);
@@ -741,40 +854,58 @@ static void import_freejob(void *user_data)
delete data;
}
-void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence, bool set_frame_range, int sequence_len, int offset, bool validate_meshes)
+bool ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence,
+ bool set_frame_range, int sequence_len, int offset,
+ bool validate_meshes, bool as_background_job)
{
/* Using new here since MEM_* funcs do not call ctor to properly initialize
* data. */
ImportJobData *job = new ImportJobData();
job->bmain = CTX_data_main(C);
job->scene = CTX_data_scene(C);
+ job->import_ok = false;
BLI_strncpy(job->filename, filepath, 1024);
job->settings.scale = scale;
job->settings.is_sequence = is_sequence;
job->settings.set_frame_range = set_frame_range;
job->settings.sequence_len = sequence_len;
- job->settings.offset = offset;
+ job->settings.sequence_offset = offset;
job->settings.validate_meshes = validate_meshes;
- job->parent_map = NULL;
job->error_code = ABC_NO_ERROR;
job->was_cancelled = false;
G.is_break = false;
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- job->scene,
- "Alembic Import",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_ALEMBIC);
+ bool import_ok = false;
+ if (as_background_job) {
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ job->scene,
+ "Alembic Import",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_ALEMBIC);
+
+ /* setup job */
+ WM_jobs_customdata_set(wm_job, job, import_freejob);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
+ WM_jobs_callbacks(wm_job, import_startjob, NULL, NULL, import_endjob);
- /* setup job */
- WM_jobs_customdata_set(wm_job, job, import_freejob);
- WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
- WM_jobs_callbacks(wm_job, import_startjob, NULL, NULL, import_endjob);
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
+ else {
+ /* Fake a job context, so that we don't need NULL pointer checks while importing. */
+ short stop = 0, do_update = 0;
+ float progress = 0.f;
+
+ import_startjob(job, &stop, &do_update, &progress);
+ import_endjob(job);
+ import_ok = job->import_ok;
+
+ import_freejob(job);
+ }
- WM_jobs_start(CTX_wm_manager(C), wm_job);
+ return import_ok;
}
/* ************************************************************************** */
@@ -809,42 +940,15 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
}
const ObjectHeader &header = iobject.getHeader();
-
- if (IPolyMesh::matches(header)) {
- if (ob->type != OB_MESH) {
- *err_str = "Object type mismatch: object path points to a mesh!";
- return NULL;
- }
-
- return abc_reader->read_derivedmesh(dm, time, read_flag);
- }
- else if (ISubD::matches(header)) {
- if (ob->type != OB_MESH) {
- *err_str = "Object type mismatch: object path points to a subdivision mesh!";
- return NULL;
- }
-
- return abc_reader->read_derivedmesh(dm, time, read_flag);
- }
- else if (IPoints::matches(header)) {
- if (ob->type != OB_MESH) {
- *err_str = "Object type mismatch: object path points to a point cloud (requires a mesh object)!";
- return NULL;
- }
-
- return abc_reader->read_derivedmesh(dm, time, read_flag);
- }
- else if (ICurves::matches(header)) {
- if (ob->type != OB_CURVE) {
- *err_str = "Object type mismatch: object path points to a curve!";
- return NULL;
- }
-
- return abc_reader->read_derivedmesh(dm, time, read_flag);
+ if (!abc_reader->accepts_object_type(header, ob, err_str)) {
+ /* err_str is set by acceptsObjectType() */
+ return NULL;
}
- *err_str = "Unsupported object type: verify object path"; // or poke developer
- return NULL;
+ /* kFloorIndex is used to be compatible with non-interpolating
+ * properties; they use the floor. */
+ ISampleSelector sample_sel(time, ISampleSelector::kFloorIndex);
+ return abc_reader->read_derivedmesh(dm, sample_sel, read_flag, err_str);
}
/* ************************************************************************** */
@@ -859,6 +963,12 @@ void CacheReader_free(CacheReader *reader)
}
}
+void CacheReader_incref(CacheReader *reader)
+{
+ AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
+ abc_reader->incref();
+}
+
CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path)
{
if (object_path[0] == '\0') {
@@ -880,6 +990,10 @@ CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, CacheRead
ImportSettings settings;
AbcObjectReader *abc_reader = create_reader(iobject, settings);
+ if (abc_reader == NULL) {
+ /* This object is not supported */
+ return NULL;
+ }
abc_reader->object(object);
abc_reader->incref();
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 1f38d64924c..8c8aef3de57 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -38,7 +38,7 @@ struct rctf;
struct ColorManagedDisplay;
struct ResultBLF;
-int BLF_init(int points, int dpi);
+int BLF_init(void);
void BLF_exit(void);
void BLF_default_dpi(int dpi);
void BLF_default_set(int fontid);
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 132a0ec3808..5bd62980b6d 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -96,15 +96,16 @@ static FontBLF *blf_get(int fontid)
return NULL;
}
-int BLF_init(int points, int dpi)
+int BLF_init(void)
{
int i;
for (i = 0; i < BLF_MAX_FONT; i++)
global_font[i] = NULL;
- global_font_points = points;
- global_font_dpi = dpi;
+ global_font_points = 11;
+ global_font_dpi = 72;
+
return blf_font_init();
}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index aa7d539538b..bbbabfb8ba2 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -135,6 +135,7 @@ void blf_glyph_cache_clear(FontBLF *font)
while ((gc = BLI_pophead(&font->cache))) {
blf_glyph_cache_free(gc);
}
+ font->glyph_cache = NULL;
}
void blf_glyph_cache_free(GlyphCacheBLF *gc)
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index 133168fccf2..b6f5ffbb092 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -98,6 +98,10 @@ void BLF_thumb_preview(
blf_font_size(font, (unsigned int)MAX2(font_size_min, font_size_curr), dpi);
+ /* font->glyph_cache remains NULL if blf_font_size() failed to set font size */
+ if (!font->glyph_cache)
+ break;
+
/* decrease font size each time */
font_size_curr -= (font_size_curr / font_shrink);
font_shrink += 1;
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 789bc8df7e5..700bfe568f1 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -193,7 +193,9 @@ struct DerivedMesh {
* \warning Typical access is done via #getLoopTriArray, #getNumLoopTri.
*/
struct {
- struct MLoopTri *array;
+ /* WARNING! swapping between array (ready-to-be-used data) and array_wip (where data is actually computed)
+ * shall always be protected by same lock as one used for looptris computing. */
+ struct MLoopTri *array, *array_wip;
int num;
int num_alloc;
} looptris;
@@ -201,7 +203,7 @@ struct DerivedMesh {
/* use for converting to BMesh which doesn't store bevel weight and edge crease by default */
char cd_flag;
- char tangent_mask; /* which tangent layers are calculated */
+ short tangent_mask; /* which tangent layers are calculated */
/** Calculate vert and face normals */
void (*calcNormals)(DerivedMesh *dm);
@@ -220,7 +222,7 @@ struct DerivedMesh {
/** Recalculates mesh tessellation */
void (*recalcTessellation)(DerivedMesh *dm);
- /** Loop tessellation cache */
+ /** Loop tessellation cache (WARNING! Only call inside threading-protected code!) */
void (*recalcLoopTri)(DerivedMesh *dm);
/** accessor functions */
const struct MLoopTri *(*getLoopTriArray)(DerivedMesh * dm);
@@ -625,7 +627,6 @@ void DM_ensure_normals(DerivedMesh *dm);
void DM_ensure_tessface(DerivedMesh *dm);
void DM_ensure_looptri_data(DerivedMesh *dm);
-void DM_ensure_looptri(DerivedMesh *dm);
void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num);
void DM_update_tessface_data(DerivedMesh *dm);
@@ -791,11 +792,13 @@ void DM_calc_tangents_names_from_gpu(
void DM_add_named_tangent_layer_for_uv(
CustomData *uv_data, CustomData *tan_data, int numLoopData,
const char *layer_name);
+
+#define DM_TANGENT_MASK_ORCO (1 << 9)
void DM_calc_loop_tangents_step_0(
const CustomData *loopData, bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME], int tangent_names_count,
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
- char *ract_uv_name, char *rren_uv_name, char *rtangent_mask);
+ char *ract_uv_name, char *rren_uv_name, short *rtangent_mask);
void DM_calc_loop_tangents(
DerivedMesh *dm, bool calc_active_tangent, const char (*tangent_names)[MAX_NAME],
int tangent_names_count);
@@ -830,11 +833,5 @@ struct MEdge *DM_get_edge_array(struct DerivedMesh *dm, bool *r_allocated);
struct MLoop *DM_get_loop_array(struct DerivedMesh *dm, bool *r_allocated);
struct MPoly *DM_get_poly_array(struct DerivedMesh *dm, bool *r_allocated);
struct MFace *DM_get_tessface_array(struct DerivedMesh *dm, bool *r_allocated);
-const MLoopTri *DM_get_looptri_array(
- DerivedMesh *dm,
- const MVert *mvert,
- const MPoly *mpoly, int mpoly_len,
- const MLoop *mloop, int mloop_len,
- bool *r_allocated);
#endif /* __BKE_DERIVEDMESH_H__ */
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 6527ba7f94f..28be2b04c71 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -57,8 +57,9 @@ extern "C" {
/* Allocate a new bAction with the given name */
struct bAction *add_empty_action(struct Main *bmain, const char name[]);
-/* Allocate a copy of the given Action and all its data */
-struct bAction *BKE_action_copy(struct Main *bmain, struct bAction *src);
+void BKE_action_copy_data(struct Main *bmain, struct bAction *act_dst, const struct bAction *act_src, const int flag);
+/* Allocate a copy of the given Action and all its data */
+struct bAction *BKE_action_copy(struct Main *bmain, const struct bAction *act_src);
/* Deallocate all of the Action's data, but not the Action itself */
void BKE_action_free(struct bAction *act);
@@ -150,7 +151,8 @@ void BKE_pose_free_data_ex(struct bPose *pose, bool do_id_user);
void BKE_pose_free_data(struct bPose *pose);
void BKE_pose_free(struct bPose *pose);
void BKE_pose_free_ex(struct bPose *pose, bool do_id_user);
-void BKE_pose_copy_data(struct bPose **dst, struct bPose *src, const bool copy_constraints);
+void BKE_pose_copy_data_ex(struct bPose **dst, const struct bPose *src, const int flag, const bool copy_constraints);
+void BKE_pose_copy_data(struct bPose **dst, const struct bPose *src, const bool copy_constraints);
void BKE_pose_channel_copy_data(struct bPoseChannel *pchan, const struct bPoseChannel *pchan_from);
struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name);
struct bPoseChannel *BKE_pose_channel_active(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 00ea323f934..534a57765f6 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -67,13 +67,13 @@ bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct b
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);
+struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const bool do_action);
/* Copy AnimData */
-bool BKE_animdata_copy_id(struct ID *id_to, struct ID *id_from, const bool do_action);
+bool BKE_animdata_copy_id(struct Main *bmain, struct ID *id_to, struct ID *id_from, const bool do_action);
/* Copy AnimData Actions */
-void BKE_animdata_copy_id_action(struct ID *id);
+void BKE_animdata_copy_id_action(struct ID *id, const bool set_newid);
/* Merge copies of data from source AnimData block */
typedef enum eAnimData_MergeCopy_Modes {
@@ -89,12 +89,6 @@ typedef enum eAnimData_MergeCopy_Modes {
void BKE_animdata_merge_copy(struct ID *dst_id, struct ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers);
-/* Make Local */
-void BKE_animdata_make_local(struct AnimData *adt);
-
-/* Re-Assign ID's */
-void BKE_animdata_relink(struct AnimData *adt);
-
/* ************************************* */
/* KeyingSets API */
@@ -108,7 +102,7 @@ struct KS_Path *BKE_keyingset_add_path(struct KeyingSet *ks, struct ID *id, cons
struct KS_Path *BKE_keyingset_find_path(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, int group_mode);
/* Copy all KeyingSets in the given list */
-void BKE_keyingsets_copy(struct ListBase *newlist, struct ListBase *list);
+void BKE_keyingsets_copy(struct ListBase *newlist, const struct ListBase *list);
/* Free the given Keying Set path */
void BKE_keyingset_free_path(struct KeyingSet *ks, struct KS_Path *ksp);
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index 077fe2a629c..ac8f861fa56 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -27,11 +27,15 @@
/* note on naming: typical _get() suffix is omitted here,
* since its the main purpose of the API. */
const char *BKE_appdir_folder_default(void);
+const char *BKE_appdir_folder_id_ex(const int folder_id, const char *subfolder, char *path, size_t path_len);
const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder);
const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder);
const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder);
const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, const bool do_check);
+bool BKE_appdir_app_template_any(void);
+bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len);
+
/* Initialize path to program executable */
void BKE_appdir_program_path_init(const char *argv0);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 78d6f6c7cb9..60fb79d75d5 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -77,7 +77,8 @@ int BKE_armature_bonelist_count(struct ListBase *lb);
void BKE_armature_bonelist_free(struct ListBase *lb);
void BKE_armature_free(struct bArmature *arm);
void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm, const bool lib_local);
-struct bArmature *BKE_armature_copy(struct Main *bmain, struct bArmature *arm);
+void BKE_armature_copy_data(struct Main *bmain, struct bArmature *arm_dst, const struct bArmature *arm_src, const int flag);
+struct bArmature *BKE_armature_copy(struct Main *bmain, const struct bArmature *arm);
/* Bounding box. */
struct BoundBox *BKE_armature_boundbox_get(struct Object *ob);
@@ -171,12 +172,18 @@ void BKE_pose_eval_init(struct EvaluationContext *eval_ctx,
struct Object *ob,
struct bPose *pose);
+void BKE_pose_eval_init_ik(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bPose *pose);
+
void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob,
struct bPoseChannel *pchan);
void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
struct Object *ob,
struct bPoseChannel *pchan);
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index d2d9c763031..ec0bfa6f5fa 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -38,14 +38,21 @@
extern "C" {
#endif
+struct UserDef;
+
void BKE_blender_free(void);
void BKE_blender_globals_init(void);
void BKE_blender_globals_clear(void);
+void BKE_blender_version_string(
+ char *version_str, size_t maxncpy,
+ short version, short subversion, bool v_prefix, bool include_subversion);
+
+void BKE_blender_userdef_set_data(struct UserDef *userdef);
+void BKE_blender_userdef_free_data(struct UserDef *userdef);
+
+void BKE_blender_userdef_set_app_template(struct UserDef *userdef);
-void BKE_blender_userdef_free(void);
-void BKE_blender_userdef_refresh(void);
-
/* set this callback when a UI is running */
void BKE_blender_callback_test_break_set(void (*func)(void));
int BKE_blender_test_break(void);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 4f4787f9da5..f95b1963a91 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,8 +27,8 @@
/* these lines are grep'd, watch out for our not-so-awesome regex
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
-#define BLENDER_VERSION 278
-#define BLENDER_SUBVERSION 4
+#define BLENDER_VERSION 279
+#define BLENDER_SUBVERSION 1
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 6
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index 6767fce3abd..ac58451e412 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -33,8 +33,7 @@ struct ID;
struct Main;
struct MemFile;
struct ReportList;
-
-int BKE_blendfile_read(struct bContext *C, const char *filepath, struct ReportList *reports);
+struct UserDef;
enum {
BKE_BLENDFILE_READ_FAIL = 0, /* no load */
@@ -42,15 +41,24 @@ enum {
BKE_BLENDFILE_READ_OK_USERPREFS = 2, /* OK, and with new user settings */
};
+int BKE_blendfile_read(
+ struct bContext *C, const char *filepath,
+ struct ReportList *reports, int skip_flag);
bool BKE_blendfile_read_from_memory(
- struct bContext *C, const void *filebuf,
- int filelength, struct ReportList *reports, bool update_defaults);
+ struct bContext *C, const void *filebuf, int filelength,
+ struct ReportList *reports, int skip_flag, bool update_defaults);
bool BKE_blendfile_read_from_memfile(
struct bContext *C, struct MemFile *memfile,
+ struct ReportList *reports, int skip_flag);
+void BKE_blendfile_read_make_empty(struct bContext *C);
+
+struct UserDef *BKE_blendfile_userdef_read(
+ const char *filepath, struct ReportList *reports);
+struct UserDef *BKE_blendfile_userdef_read_from_memory(
+ const void *filebuf, int filelength,
struct ReportList *reports);
-int BKE_blendfile_read_userdef(const char *filepath, struct ReportList *reports);
-int BKE_blendfile_write_userdef(const char *filepath, struct ReportList *reports);
+int BKE_blendfile_userdef_write(const char *filepath, struct ReportList *reports);
/* partial blend file writing */
diff --git a/source/blender/blenkernel/BKE_boids.h b/source/blender/blenkernel/BKE_boids.h
index 582cd0cef8d..24f19951efe 100644
--- a/source/blender/blenkernel/BKE_boids.h
+++ b/source/blender/blenkernel/BKE_boids.h
@@ -61,6 +61,6 @@ BoidRule *boid_new_rule(int type);
BoidState *boid_new_state(BoidSettings *boids);
BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state);
void boid_free_settings(BoidSettings *boids);
-BoidSettings *boid_copy_settings(BoidSettings *boids);
+BoidSettings *boid_copy_settings(const BoidSettings *boids);
BoidState *boid_get_current_state(BoidSettings *boids);
#endif
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 8bd4bdf89e1..7c2873046d5 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -44,7 +44,8 @@ void BKE_brush_system_exit(void);
void BKE_brush_init(struct Brush *brush);
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode);
struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode);
-struct Brush *BKE_brush_copy(struct Main *bmain, struct Brush *brush);
+void BKE_brush_copy_data(struct Main *bmain, struct Brush *brush_dst, const struct Brush *brush_src, const int flag);
+struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush);
void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local);
void BKE_brush_unlink(struct Main *bmain, struct Brush *brush);
void BKE_brush_free(struct Brush *brush);
@@ -69,11 +70,11 @@ void BKE_brush_randomize_texture_coords(struct UnifiedPaintSettings *ups, bool m
/* brush curve */
void BKE_brush_curve_preset(struct Brush *b, int preset);
float BKE_brush_curve_strength_clamped(struct Brush *br, float p, const float len);
-float BKE_brush_curve_strength(struct Brush *br, float p, const float len);
+float BKE_brush_curve_strength(const struct Brush *br, float p, const float len);
/* sampling */
float BKE_brush_sample_tex_3D(
- const struct Scene *scene, struct Brush *br, const float point[3],
+ const struct Scene *scene, const struct Brush *br, const float point[3],
float rgba[4], const int thread, struct ImagePool *pool);
float BKE_brush_sample_masktex(
const struct Scene *scene, struct Brush *br, const float point[2],
@@ -102,9 +103,11 @@ void BKE_brush_alpha_set(struct Scene *scene, struct Brush *brush, float alpha);
float BKE_brush_weight_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_weight_set(const struct Scene *scene, struct Brush *brush, float value);
-int BKE_brush_use_locked_size(const struct Scene *scene, const struct Brush *brush);
-int BKE_brush_use_alpha_pressure(const struct Scene *scene, const struct Brush *brush);
-int BKE_brush_use_size_pressure(const struct Scene *scene, const struct Brush *brush);
+bool BKE_brush_use_locked_size(const struct Scene *scene, const struct Brush *brush);
+bool BKE_brush_use_alpha_pressure(const struct Scene *scene, const struct Brush *brush);
+bool BKE_brush_use_size_pressure(const struct Scene *scene, const struct Brush *brush);
+
+bool BKE_brush_sculpt_has_secondary_color(const struct Brush *brush);
/* scale unprojected radius to reflect a change in the brush's 2D size */
void BKE_brush_scale_unprojected_radius(
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 07db2217bac..cb72f0859d5 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -54,7 +54,6 @@ typedef struct BVHTreeFromEditMesh {
/* default callbacks to bvh nearest and raycast */
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
- BVHTree_NearestToRayCallback nearest_to_ray_callback;
struct BMEditMesh *em;
@@ -75,7 +74,6 @@ typedef struct BVHTreeFromMesh {
/* default callbacks to bvh nearest and raycast */
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
- BVHTree_NearestToRayCallback nearest_to_ray_callback;
/* Vertex array, so that callbacks have instante access to data */
const struct MVert *vert;
@@ -104,7 +102,7 @@ typedef struct BVHTreeFromMesh {
* The tree is build in mesh space coordinates, this means special care must be made on queries
* so that the coordinates and rays are first translated on the mesh local coordinates.
* Reason for this is that bvh_from_mesh_* can use a cache in some cases and so it becomes possible to reuse a BVHTree.
- *
+ *
* free_bvhtree_from_mesh should be called when the tree is no longer needed.
*/
BVHTree *bvhtree_from_editmesh_verts(
@@ -118,7 +116,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(
BVHTree *bvhtree_from_mesh_verts(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_mesh_verts_ex(
- struct BVHTreeFromMesh *data, struct MVert *vert, const int numVerts,
+ struct BVHTreeFromMesh *data, const struct MVert *vert, const int numVerts,
const bool vert_allocated, const BLI_bitmap *mask, int verts_num_active,
float epsilon, int tree_type, int axis);
@@ -133,14 +131,20 @@ BVHTree *bvhtree_from_editmesh_edges_ex(
BVHTree *bvhtree_from_mesh_edges(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh,
float epsilon, int tree_type, int axis);
+BVHTree *bvhtree_from_mesh_edges_ex(
+ struct BVHTreeFromMesh *data,
+ const struct MVert *vert, const bool vert_allocated,
+ const struct MEdge *edge, const int edges_num, const bool edge_allocated,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_mesh_faces(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon,
int tree_type, int axis);
BVHTree *bvhtree_from_mesh_faces_ex(
struct BVHTreeFromMesh *data,
- struct MVert *vert, const bool vert_allocated,
- struct MFace *face, const int numFaces, const bool face_allocated,
+ const struct MVert *vert, const bool vert_allocated,
+ const struct MFace *face, const int numFaces, const bool face_allocated,
const BLI_bitmap *mask, int numFaces_active,
float epsilon, int tree_type, int axis);
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h
index 7e1c069df9a..e9712681090 100644
--- a/source/blender/blenkernel/BKE_cachefile.h
+++ b/source/blender/blenkernel/BKE_cachefile.h
@@ -47,7 +47,9 @@ void BKE_cachefile_init(struct CacheFile *cache_file);
void BKE_cachefile_free(struct CacheFile *cache_file);
-struct CacheFile *BKE_cachefile_copy(struct Main *bmain, struct CacheFile *cache_file);
+void BKE_cachefile_copy_data(
+ struct Main *bmain, struct CacheFile *cache_file_dst, const struct CacheFile *cache_file_src, const int flag);
+struct CacheFile *BKE_cachefile_copy(struct Main *bmain, const struct CacheFile *cache_file);
void BKE_cachefile_make_local(struct Main *bmain, struct CacheFile *cache_file, const bool lib_local);
@@ -55,7 +57,7 @@ void BKE_cachefile_reload(const struct Main *bmain, struct CacheFile *cache_file
void BKE_cachefile_ensure_handle(const struct Main *bmain, struct CacheFile *cache_file);
-void BKE_cachefile_update_frame(struct Main *bmain, struct Scene *scene,const float ctime, const float fps);
+void BKE_cachefile_update_frame(struct Main *bmain, struct Scene *scene, const float ctime, const float fps);
bool BKE_cachefile_filepath_get(
const struct Main *bmain, const struct CacheFile *cache_file, float frame,
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index 31a732cf7e5..04dee70faa6 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -52,7 +52,8 @@ struct GPUFXSettings;
void BKE_camera_init(struct Camera *cam);
void *BKE_camera_add(struct Main *bmain, const char *name);
-struct Camera *BKE_camera_copy(struct Main *bmain, struct Camera *cam);
+void BKE_camera_copy_data(struct Main *bmain, struct Camera *cam_dst, const struct Camera *cam_src, const int flag);
+struct Camera *BKE_camera_copy(struct Main *bmain, const struct Camera *cam);
void BKE_camera_make_local(struct Main *bmain, struct Camera *cam, const bool lib_local);
void BKE_camera_free(struct Camera *ca);
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index 9948f21ba90..4876461bfe0 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -79,6 +79,7 @@ DerivedMesh *CDDM_from_curve_displist(struct Object *ob, struct ListBase *dispba
*/
struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm);
struct DerivedMesh *CDDM_copy_from_tessface(struct DerivedMesh *dm);
+struct DerivedMesh *CDDM_copy_with_tessface(struct DerivedMesh *dm);
/* creates a CDDerivedMesh with the same layer stack configuration as the
* given DerivedMesh and containing the requested numbers of elements.
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 36330242f18..6c517bd02df 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -136,9 +136,6 @@ typedef struct ClothSpring {
float restlen; /* The original length of the spring. */
int type; /* types defined in BKE_cloth.h ("springType") */
int flags; /* defined in BKE_cloth.h, e.g. deactivated due to tearing */
- float dfdx[3][3];
- float dfdv[3][3];
- float f[3];
float stiffness; /* stiffness factor from the vertex groups */
float editrestlen;
@@ -240,9 +237,6 @@ void bvhselftree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
// needed for button_object.c
void cloth_clear_cache (struct Object *ob, struct ClothModifierData *clmd, float framenr );
-// needed for cloth.c
-int cloth_add_spring (struct ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type);
-
void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3]);
////////////////////////////////////////////////
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index 5b4f5910821..f68c4a2757b 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -46,8 +46,8 @@ void curvemapping_set_defaults(struct CurveMapping *cumap, int to
struct CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy);
void curvemapping_free_data(struct CurveMapping *cumap);
void curvemapping_free(struct CurveMapping *cumap);
-void curvemapping_copy_data(struct CurveMapping *target, struct CurveMapping *cumap);
-struct CurveMapping *curvemapping_copy(struct CurveMapping *cumap);
+void curvemapping_copy_data(struct CurveMapping *target, const struct CurveMapping *cumap);
+struct CurveMapping *curvemapping_copy(const struct CurveMapping *cumap);
void curvemapping_set_black_white_ex(const float black[3], const float white[3], float r_bwmul[3]);
void curvemapping_set_black_white(struct CurveMapping *cumap, const float black[3], const float white[3]);
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index 047d1787f76..4e0eb5c65ac 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -120,6 +120,7 @@ void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list);
void BKE_constraints_free(struct ListBase *list);
void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user);
void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern);
+void BKE_constraints_copy_ex(struct ListBase *dst, const struct ListBase *src, const int flag, bool do_extern);
void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void *userdata);
void BKE_constraint_free_data(struct bConstraint *con);
void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user);
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 5558786d254..a900ba43443 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -36,6 +36,7 @@
struct BezTriple;
struct Curve;
struct EditNurb;
+struct GHash;
struct ListBase;
struct Main;
struct Nurb;
@@ -52,6 +53,13 @@ typedef struct CurveCache {
struct Path *path;
} CurveCache;
+/* Definitions needed for shape keys */
+typedef struct CVKeyIndex {
+ void *orig_cv;
+ int key_index, nu_index, pt_index, vertex_index;
+ bool switched;
+} CVKeyIndex;
+
#define KNOTSU(nu) ( (nu)->orderu + (nu)->pntsu + (((nu)->flagu & CU_NURB_CYCLIC) ? ((nu)->orderu - 1) : 0) )
#define KNOTSV(nu) ( (nu)->orderv + (nu)->pntsv + (((nu)->flagv & CU_NURB_CYCLIC) ? ((nu)->orderv - 1) : 0) )
@@ -70,7 +78,8 @@ void BKE_curve_free(struct Curve *cu);
void BKE_curve_editfont_free(struct Curve *cu);
void BKE_curve_init(struct Curve *cu);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
-struct Curve *BKE_curve_copy(struct Main *bmain, struct Curve *cu);
+void BKE_curve_copy_data(struct Main *bmain, struct Curve *cu_dst, const struct Curve *cu_src, const int flag);
+struct Curve *BKE_curve_copy(struct Main *bmain, const struct Curve *cu);
void BKE_curve_make_local(struct Main *bmain, struct Curve *cu, const bool lib_local);
short BKE_curve_type_get(struct Curve *cu);
void BKE_curve_type_test(struct Object *ob);
@@ -84,8 +93,8 @@ void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_rot[3], fl
bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]);
bool BKE_curve_center_median(struct Curve *cu, float cent[3]);
bool BKE_curve_center_bounds(struct Curve *cu, float cent[3]);
-void BKE_curve_transform_ex(struct Curve *cu, float mat[4][4], const bool do_keys, const float unit_scale);
-void BKE_curve_transform(struct Curve *cu, float mat[4][4], const bool do_keys);
+void BKE_curve_transform_ex(struct Curve *cu, float mat[4][4], const bool do_keys, const bool do_props, const float unit_scale);
+void BKE_curve_transform(struct Curve *cu, float mat[4][4], const bool do_keys, const bool do_props);
void BKE_curve_translate(struct Curve *cu, float offset[3], const bool do_keys);
void BKE_curve_material_index_remove(struct Curve *cu, int index);
void BKE_curve_material_index_clear(struct Curve *cu);
@@ -108,7 +117,8 @@ void BK_curve_nurbs_vertexCos_apply(struct ListBase *lb, float (*vertexCos)[3]);
float (*BKE_curve_nurbs_keyVertexCos_get(struct ListBase *lb, float *key))[3];
void BKE_curve_nurbs_keyVertexTilts_apply(struct ListBase *lb, float *key);
-void BKE_curve_editNurb_keyIndex_free(struct EditNurb *editnurb);
+void BKE_curve_editNurb_keyIndex_delCV(struct GHash *keyindex, const void *cv);
+void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex);
void BKE_curve_editNurb_free(struct Curve *cu);
struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu);
@@ -133,7 +143,7 @@ int BKE_nurbList_verts_count(struct ListBase *nurb);
int BKE_nurbList_verts_count_without_handles(struct ListBase *nurb);
void BKE_nurbList_free(struct ListBase *lb);
-void BKE_nurbList_duplicate(struct ListBase *lb1, struct ListBase *lb2);
+void BKE_nurbList_duplicate(struct ListBase *lb1, const struct ListBase *lb2);
void BKE_nurbList_handles_set(struct ListBase *editnurb, const char code);
void BKE_nurbList_handles_recalculate(struct ListBase *editnurb, const bool calc_length, const char flag);
@@ -141,7 +151,7 @@ void BKE_nurbList_handles_autocalc(ListBase *editnurb, int flag);
void BKE_nurbList_flag_set(ListBase *editnurb, short flag);
void BKE_nurb_free(struct Nurb *nu);
-struct Nurb *BKE_nurb_duplicate(struct Nurb *nu);
+struct Nurb *BKE_nurb_duplicate(const struct Nurb *nu);
struct Nurb *BKE_nurb_copy(struct Nurb *src, int pntsu, int pntsv);
void BKE_nurb_test2D(struct Nurb *nu);
@@ -189,6 +199,7 @@ void BKE_nurb_bezt_calc_normal(struct Nurb *nu, struct BezTriple *bezt, float r_
void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_plane[3]);
void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_normal[3]);
+void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, struct BPoint *bp, float r_plane[3]);
void BKE_nurb_handle_calc(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next,
const bool is_fcurve);
@@ -207,7 +218,4 @@ struct EvaluationContext;
void BKE_curve_eval_geometry(struct EvaluationContext *eval_ctx,
struct Curve *curve);
-void BKE_curve_eval_path(struct EvaluationContext *eval_ctx,
- struct Curve *curve);
-
#endif /* __BKE_CURVE_H__ */
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index 8756f73df72..a20c5a4240c 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -44,8 +44,8 @@ struct MLoop;
struct MPoly;
struct bDeformGroup *BKE_defgroup_new(struct Object *ob, const char *name);
-void defgroup_copy_list(struct ListBase *lb1, struct ListBase *lb2);
-struct bDeformGroup *defgroup_duplicate(struct bDeformGroup *ingroup);
+void defgroup_copy_list(struct ListBase *lb1, const struct ListBase *lb2);
+struct bDeformGroup *defgroup_duplicate(const struct bDeformGroup *ingroup);
struct bDeformGroup *defgroup_find_name(struct Object *ob, const char *name);
int *defgroup_flip_map(struct Object *ob, int *flip_map_len, const bool use_default);
int *defgroup_flip_map_single(struct Object *ob, int *flip_map_len, const bool use_default, int defgroup);
@@ -116,13 +116,4 @@ void BKE_defvert_extract_vgroup_to_polyweights(
struct MDeformVert *dvert, const int defgroup, const int num_verts, struct MLoop *loops, const int num_loops,
struct MPoly *polys, const int num_polys, float *r_weights, const bool invert_vgroup);
-/* utility function, note that MAX_VGROUP_NAME chars is the maximum string length since its only
- * used with defgroups currently */
-
-void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char base[MAX_VGROUP_NAME], char ext[MAX_VGROUP_NAME]);
-void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char base[MAX_VGROUP_NAME], char ext[MAX_VGROUP_NAME]);
-
-void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME],
- const bool strip_number);
-
#endif /* __BKE_DEFORM_H__ */
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index b934ec7166d..aa45132cbe9 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -172,6 +172,7 @@ typedef struct SimDebugElement {
float color[3];
float v1[3], v2[3];
+ char str[64];
} SimDebugElement;
typedef enum eSimDebugElement_Type {
@@ -179,6 +180,7 @@ typedef enum eSimDebugElement_Type {
SIM_DEBUG_ELEM_CIRCLE,
SIM_DEBUG_ELEM_LINE,
SIM_DEBUG_ELEM_VECTOR,
+ SIM_DEBUG_ELEM_STRING,
} eSimDebugElement_Type;
typedef struct SimDebugData {
@@ -191,26 +193,30 @@ void BKE_sim_debug_data_set_enabled(bool enable);
bool BKE_sim_debug_data_get_enabled(void);
void BKE_sim_debug_data_free(void);
-void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3],
+void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], const char *str,
float r, float g, float b, const char *category, unsigned int hash);
void BKE_sim_debug_data_remove_element(unsigned int hash);
#define BKE_sim_debug_data_add_dot(p, r, g, b, category, ...) { \
const float v2[3] = { 0.0f, 0.0f, 0.0f }; \
- BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_DOT, p, v2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_DOT, p, v2, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
}
#define BKE_sim_debug_data_add_circle(p, radius, r, g, b, category, ...) { \
const float v2[3] = { radius, 0.0f, 0.0f }; \
- BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_CIRCLE, p, v2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_CIRCLE, p, v2, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
}
#define BKE_sim_debug_data_add_line(p1, p2, r, g, b, category, ...) { \
- BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_LINE, p1, p2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_LINE, p1, p2, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
}
#define BKE_sim_debug_data_add_vector(p, d, r, g, b, category, ...) { \
- BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_VECTOR, p, d, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_VECTOR, p, d, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+}
+
+#define BKE_sim_debug_data_add_string(p, str, r, g, b, category, ...) { \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_STRING, p, NULL, str, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
}
#define BKE_sim_debug_data_remove(...) \
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 3a45097efc5..b38f1299763 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -92,7 +92,7 @@ void bezt_add_to_cfra_elem(ListBase *lb, struct BezTriple *bezt);
/* ---------------------- */
void fcurve_free_driver(struct FCurve *fcu);
-struct ChannelDriver *fcurve_copy_driver(struct ChannelDriver *driver);
+struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
void driver_variables_copy(struct ListBase *dst_list, const struct ListBase *src_list);
@@ -138,7 +138,7 @@ typedef struct FModifierTypeInfo {
/* free any data that is allocated separately (optional) */
void (*free_data)(struct FModifier *fcm);
/* copy any special data that is allocated separately (optional) */
- void (*copy_data)(struct FModifier *fcm, struct FModifier *src);
+ void (*copy_data)(struct FModifier *fcm, const struct FModifier *src);
/* set settings for data that will be used for FCuModifier.data (memory already allocated using MEM_callocN) */
void (*new_data)(void *mdata);
/* verifies that the modifier settings are valid */
@@ -183,14 +183,14 @@ typedef enum eFMI_Requirement_Flags {
} eFMI_Requirement_Flags;
/* Function Prototypes for FModifierTypeInfo's */
-const FModifierTypeInfo *fmodifier_get_typeinfo(struct FModifier *fcm);
-const FModifierTypeInfo *get_fmodifier_typeinfo(int type);
+const FModifierTypeInfo *fmodifier_get_typeinfo(const struct FModifier *fcm);
+const FModifierTypeInfo *get_fmodifier_typeinfo(const int type);
/* ---------------------- */
struct FModifier *add_fmodifier(ListBase *modifiers, int type);
-struct FModifier *copy_fmodifier(struct FModifier *src);
-void copy_fmodifiers(ListBase *dst, ListBase *src);
+struct FModifier *copy_fmodifier(const struct FModifier *src);
+void copy_fmodifiers(ListBase *dst, const ListBase *src);
bool remove_fmodifier(ListBase *modifiers, struct FModifier *fcm);
void free_fmodifiers(ListBase *modifiers);
@@ -216,7 +216,7 @@ int BKE_fcm_envelope_find_index(struct FCM_EnvelopeData *array, float frame, int
/* -------- Data Management -------- */
void free_fcurve(struct FCurve *fcu);
-struct FCurve *copy_fcurve(struct FCurve *fcu);
+struct FCurve *copy_fcurve(const struct FCurve *fcu);
void free_fcurves(ListBase *list);
void copy_fcurves(ListBase *dst, ListBase *src);
diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h
index 6775639125f..60ad061bf77 100644
--- a/source/blender/blenkernel/BKE_font.h
+++ b/source/blender/blenkernel/BKE_font.h
@@ -60,8 +60,9 @@ typedef struct EditFont {
struct CharInfo *textbufinfo;
/* array of rectangles & rotation */
- EditFontSelBox *selboxes;
float textcurs[4][2];
+ EditFontSelBox *selboxes;
+ int selboxes_len;
/* positional vars relative to the textbuf, textbufinfo (not utf8 bytes)
* a copy of these is kept in Curve, but use these in editmode */
@@ -77,6 +78,7 @@ void BKE_vfont_builtin_register(void *mem, int size);
void BKE_vfont_free_data(struct VFont *vfont);
void BKE_vfont_free(struct VFont *sc);
void BKE_vfont_init(struct VFont *vfont);
+void BKE_vfont_copy_data(struct Main *bmain, struct VFont *vfont_dst, const struct VFont *vfont_src, const int flag);
struct VFont *BKE_vfont_builtin_get(void);
struct VFont *BKE_vfont_load(struct Main *bmain, const char *filepath);
struct VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists);
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index 50407f3bdfc..1045fde0039 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -50,7 +50,7 @@ typedef struct FreestyleModuleSettings FreestyleModuleSettings;
/* FreestyleConfig */
void BKE_freestyle_config_init(FreestyleConfig *config);
void BKE_freestyle_config_free(FreestyleConfig *config);
-void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config);
+void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag);
/* FreestyleConfig.modules */
FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config);
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 5ef5a807f63..790c8051ace 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -83,8 +83,6 @@ typedef struct Global {
/* debug flag, G_DEBUG, G_DEBUG_PYTHON & friends, set python or command line args */
int debug;
- bool have_quicktime;
-
/* this variable is written to / read from FileGlobal->fileflags */
int fileflags;
@@ -129,10 +127,11 @@ enum {
G_DEBUG_GPU_MEM = (1 << 10), /* gpu memory in status bar */
G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 11), /* single threaded depsgraph */
G_DEBUG_GPU = (1 << 12), /* gpu debug */
+ G_DEBUG_IO = (1 << 13), /* IO Debugging (for Collada, ...)*/
};
#define G_DEBUG_ALL (G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS | \
- G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH | G_DEBUG_GPU_MEM)
+ G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH | G_DEBUG_GPU_MEM | G_DEBUG_IO)
/* G.fileflags */
@@ -188,11 +187,6 @@ enum {
# error Either __BIG_ENDIAN__ or __LITTLE_ENDIAN__ must be defined.
#endif
-/* there is really no good place for this */
-#if defined(FREE_WINDOWS) && ((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 6)))
-# error "Mingw requires GCC 4.6 minimum"
-#endif
-
#define L_ENDIAN 1
#define B_ENDIAN 0
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index ab8b83f8271..b6de922c245 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -60,7 +60,8 @@ struct bGPdata *BKE_gpencil_data_addnew(const char name[]);
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
-struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
+void BKE_gpencil_copy_data(struct Main *bmain, struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag);
+struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy);
void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
@@ -104,7 +105,7 @@ void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts);
void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
-void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *palette);
+void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *brush);
struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd);
void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index 09a069ee36f..404d1704c78 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -42,7 +42,8 @@ struct Scene;
void BKE_group_free(struct Group *group);
struct Group *BKE_group_add(struct Main *bmain, const char *name);
-struct Group *BKE_group_copy(struct Main *bmain, struct Group *group);
+void BKE_group_copy_data(struct Main *bmain, struct Group *group_dst, const struct Group *group_src, const int flag);
+struct Group *BKE_group_copy(struct Main *bmain, const struct Group *group);
void BKE_group_make_local(struct Main *bmain, struct Group *group, const bool lib_local);
bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
bool BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 6944c5ccd28..39e6b145755 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -88,7 +88,7 @@ void BKE_previewimg_clear(struct PreviewImage *prv);
void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size);
/* get the preview from any pointer */
-struct PreviewImage **BKE_previewimg_id_get_p(struct ID *id);
+struct PreviewImage **BKE_previewimg_id_get_p(const struct ID *id);
/* free the preview image belonging to the id */
void BKE_previewimg_id_free(struct ID *id);
@@ -97,9 +97,9 @@ void BKE_previewimg_id_free(struct ID *id);
struct PreviewImage *BKE_previewimg_create(void);
/* create a copy of the preview image */
-struct PreviewImage *BKE_previewimg_copy(struct PreviewImage *prv);
+struct PreviewImage *BKE_previewimg_copy(const struct PreviewImage *prv);
-void BKE_previewimg_id_copy(struct ID *new_id, struct ID *old_id);
+void BKE_previewimg_id_copy(struct ID *new_id, const struct ID *old_id);
/* retrieve existing or create new preview image */
struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id);
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 5b10d7ebc06..5d8cd02756d 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -58,9 +58,7 @@ typedef union IDPropertyTemplate {
/* ----------- Property Array Type ---------- */
IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-IDProperty *IDP_CopyIDPArray(const IDProperty *array) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-
-void IDP_FreeIDPArray(IDProperty *prop);
+IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* shallow copies item */
void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item) ATTR_NONNULL();
@@ -81,8 +79,8 @@ void IDP_ConcatString(struct IDProperty *str1, struct IDProperty *append) ATTR_N
void IDP_FreeString(struct IDProperty *prop) ATTR_NONNULL();
/*-------- ID Type -------*/
-void IDP_LinkID(struct IDProperty *prop, ID *id);
-void IDP_UnlinkID(struct IDProperty *prop);
+
+typedef void(*IDPWalkFunc)(void *userData, IDProperty *idp);
/*-------- Group Functions -------*/
@@ -105,6 +103,7 @@ IDProperty *IDP_GetPropertyTypeFromGroup(struct IDProperty *prop, const char *na
/*-------- Main Functions --------*/
struct IDProperty *IDP_GetProperties(struct ID *id, const bool create_if_needed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
struct IDProperty *IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+struct IDProperty *IDP_CopyProperty_ex(const struct IDProperty *prop, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is_strict) ATTR_WARN_UNUSED_RESULT;
@@ -112,11 +111,12 @@ bool IDP_EqualsProperties(struct IDProperty *prop1, struct IDProperty *prop2) AT
struct IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void IDP_FreeProperty_ex(struct IDProperty *prop, const bool do_id_user);
void IDP_FreeProperty(struct IDProperty *prop);
void IDP_ClearProperty(IDProperty *prop);
-void IDP_UnlinkProperty(struct IDProperty *prop);
+void IDP_RelinkProperty(struct IDProperty *prop);
#define IDP_Int(prop) ((prop)->data.val)
#define IDP_Array(prop) ((prop)->data.pointer)
@@ -134,11 +134,15 @@ void IDP_UnlinkProperty(struct IDProperty *prop);
# define IDP_IDPArray(prop) _Generic((prop), \
IDProperty *: ((IDProperty *) (prop)->data.pointer), \
const IDProperty *: ((const IDProperty *) (prop)->data.pointer))
+# define IDP_Id(prop) _Generic((prop), \
+ IDProperty *: ((ID *) (prop)->data.pointer), \
+ const IDProperty *: ((const ID *) (prop)->data.pointer))
#else
# define IDP_Float(prop) (*(float *)&(prop)->data.val)
# define IDP_Double(prop) (*(double *)&(prop)->data.val)
# define IDP_String(prop) ((char *) (prop)->data.pointer)
# define IDP_IDPArray(prop) ((IDProperty *) (prop)->data.pointer)
+# define IDP_Id(prop) ((ID *) (prop)->data.pointer)
#endif
#ifndef NDEBUG
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 132c73209d1..3c716f39dd0 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -58,6 +58,7 @@ void BKE_images_exit(void);
void BKE_image_free_packedfiles(struct Image *image);
void BKE_image_free_views(struct Image *image);
void BKE_image_free_buffers(struct Image *image);
+void BKE_image_free_buffers_ex(struct Image *image, bool do_lock);
/* call from library */
void BKE_image_free(struct Image *image);
@@ -250,7 +251,8 @@ void BKE_image_packfiles_from_mem(struct ReportList *reports, struct Image *ima,
void BKE_image_print_memlist(void);
/* empty image block, of similar type and filename */
-struct Image *BKE_image_copy(struct Main *bmain, struct Image *ima);
+void BKE_image_copy_data(struct Main *bmain, struct Image *ima_dst, const struct Image *ima_src, const int flag);
+struct Image *BKE_image_copy(struct Main *bmain, const struct Image *ima);
/* merge source into dest, and free source */
void BKE_image_merge(struct Image *dest, struct Image *source);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index e590ff148d7..5eef44ef896 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -51,7 +51,8 @@ extern "C" {
void BKE_key_free(struct Key *sc);
void BKE_key_free_nolib(struct Key *key);
struct Key *BKE_key_add(struct ID *id);
-struct Key *BKE_key_copy(struct Main *bmain, struct Key *key);
+void BKE_key_copy_data(struct Main *bmain, struct Key *key_dst, const struct Key *key_src, const int flag);
+struct Key *BKE_key_copy(struct Main *bmain, const struct Key *key);
struct Key *BKE_key_copy_nolib(struct Key *key);
void BKE_key_sort(struct Key *key);
diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h
index 4d53850c572..b68da654520 100644
--- a/source/blender/blenkernel/BKE_lamp.h
+++ b/source/blender/blenkernel/BKE_lamp.h
@@ -44,7 +44,8 @@ struct Scene;
void BKE_lamp_init(struct Lamp *la);
struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT;
-struct Lamp *BKE_lamp_copy(struct Main *bmain, struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
+void BKE_lamp_copy_data(struct Main *bmain, struct Lamp *la_dst, const struct Lamp *la_src, const int flag);
+struct Lamp *BKE_lamp_copy(struct Main *bmain, const struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool lib_local);
void BKE_lamp_free(struct Lamp *la);
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 226c82da295..f7d006785d2 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -47,7 +47,8 @@ struct MDeformVert;
void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb);
void BKE_lattice_init(struct Lattice *lt);
struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name);
-struct Lattice *BKE_lattice_copy(struct Main *bmain, struct Lattice *lt);
+void BKE_lattice_copy_data(struct Main *bmain, struct Lattice *lt_dst, const struct Lattice *lt_src, const int flag);
+struct Lattice *BKE_lattice_copy(struct Main *bmain, const struct Lattice *lt);
void BKE_lattice_free(struct Lattice *lt);
void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local);
void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du);
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 855eb10976c..b5104b35b3c 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -50,13 +50,40 @@ struct bContext;
struct PointerRNA;
struct PropertyRNA;
+size_t BKE_libblock_get_alloc_info(short type, const char **name);
void *BKE_libblock_alloc_notest(short type);
-void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BKE_libblock_init_empty(struct ID *id);
-void *BKE_libblock_copy(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL();
-void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action);
-void BKE_libblock_relink(struct ID *id);
+
+/**
+ * New ID creation/copying options.
+ */
+enum {
+ /* *** Generic options (should be handled by all ID types copying, ID creation, etc.). *** */
+ /* Create datablock outside of any main database - similar to 'localize' functions of materials etc. */
+ LIB_ID_CREATE_NO_MAIN = 1 << 0,
+ /* Do not affect user refcount of datablocks used by new one (which also gets zero usercount then).
+ * Implies LIB_ID_CREATE_NO_MAIN. */
+ LIB_ID_CREATE_NO_USER_REFCOUNT = 1 << 1,
+ /* Assume given 'newid' already points to allocated memory for whole datablock (ID + data) - USE WITH CAUTION!
+ * Implies LIB_ID_CREATE_NO_MAIN. */
+ LIB_ID_CREATE_NO_ALLOCATE = 1 << 2,
+
+ LIB_ID_CREATE_NO_DEG_TAG = 1 << 8, /* Do not tag new ID for update in depsgraph. */
+
+ /* Specific options to some ID types or usages, may be ignored by unrelated ID copying functions. */
+ LIB_ID_COPY_NO_PROXY_CLEAR = 1 << 16, /* Object only, needed by make_local code. */
+ LIB_ID_COPY_NO_PREVIEW = 1 << 17, /* Do not copy preview data, when supported. */
+ LIB_ID_COPY_CACHES = 1 << 18, /* Copy runtime data caches. */
+ /* XXX TODO Do we want to keep that? would rather try to get rid of it... */
+ LIB_ID_COPY_ACTIONS = 1 << 19, /* EXCEPTION! Deep-copy actions used by animdata of copied ID. */
+};
+
+void BKE_libblock_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag);
+void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/* "Deprecated" old API. */
+void *BKE_libblock_copy_nolib(const struct ID *id, const bool do_action) ATTR_NONNULL();
+
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();
@@ -64,12 +91,45 @@ struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const
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();
+/**
+ * New freeing logic options.
+ */
+enum {
+ /* *** Generic options (should be handled by all ID types freeing). *** */
+ /* Do not try to remove freed ID from given Main (passed Main may be NULL). */
+ LIB_ID_FREE_NO_MAIN = 1 << 0,
+ /* Do not affect user refcount of datablocks used by freed one.
+ * Implies LIB_ID_FREE_NO_MAIN. */
+ LIB_ID_FREE_NO_USER_REFCOUNT = 1 << 1,
+ /* Assume freed ID datablock memory is managed elsewhere, do not free it
+ * (still calls relevant ID type's freeing function though) - USE WITH CAUTION!
+ * Implies LIB_ID_FREE_NO_MAIN. */
+ LIB_ID_FREE_NOT_ALLOCATED = 1 << 2,
+
+ LIB_ID_FREE_NO_DEG_TAG = 1 << 8, /* Do not tag freed ID for update in depsgraph. */
+ LIB_ID_FREE_NO_UI_USER = 1 << 9, /* Do not attempt to remove freed ID from UI data/notifiers/... */
+};
+
+void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, const bool use_flag_from_idtag);
+void BKE_id_free(struct Main *bmain, void *idv);
+/* Those three naming are bad actually, should be BKE_id_free... (since it goes beyond mere datablock). */
+/* "Deprecated" old API */
void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user) ATTR_NONNULL();
+void BKE_libblock_free(struct Main *bmain, void *idv) 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();
+
+void BKE_libblock_management_main_add(struct Main *bmain, void *idv);
+void BKE_libblock_management_main_remove(struct Main *bmain, void *idv);
+
+void BKE_libblock_management_usercounts_set(struct Main *bmain, void *idv);
+void BKE_libblock_management_usercounts_clear(struct Main *bmain, void *idv);
+
+/* TODO should be named "BKE_id_delete()". */
void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
+void BKE_libblock_free_datablock(struct ID *id, const int flag) ATTR_NONNULL();
+void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL();
+
void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
void id_lib_extern(struct ID *id);
void BKE_library_filepath_set(struct Library *lib, const char *filepath);
@@ -80,14 +140,16 @@ void id_us_plus(struct ID *id);
void id_us_min(struct ID *id);
void id_fake_user_set(struct ID *id);
void id_fake_user_clear(struct ID *id);
+void BKE_id_clear_newpoin(struct ID *id);
void BKE_id_make_local_generic(struct Main *bmain, struct ID *id, const bool id_in_mainlist, const bool lib_local);
bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local);
bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
-bool id_copy(struct Main *bmain, struct ID *id, struct ID **newid, bool test);
+bool id_copy(struct Main *bmain, const struct ID *id, struct ID **newid, bool test);
+bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag, const bool test);
void id_sort_by_name(struct ListBase *lb, struct ID *id);
-void BKE_id_expand_local(struct ID *id);
-void BKE_id_copy_ensure_local(struct Main *bmain, struct ID *old_id, struct ID *new_id);
+void BKE_id_expand_local(struct Main *bmain, struct ID *id);
+void BKE_id_copy_ensure_local(struct Main *bmain, const struct ID *old_id, struct ID *new_id);
bool new_id(struct ListBase *lb, struct ID *id, const char *name);
void id_clear_lib_data(struct Main *bmain, struct ID *id);
@@ -105,6 +167,9 @@ void BKE_main_free(struct Main *mainvar);
void BKE_main_lock(struct Main *bmain);
void BKE_main_unlock(struct Main *bmain);
+void BKE_main_relations_create(struct Main *bmain);
+void BKE_main_relations_free(struct Main *bmain);
+
struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img);
struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
void BKE_main_thumbnail_create(struct Main *bmain);
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index a7470107c24..d6e7d98f371 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -36,25 +36,33 @@ struct Main;
/* Tips for the callback for cases it's gonna to modify the pointer. */
enum {
- IDWALK_NOP = 0,
- IDWALK_NEVER_NULL = (1 << 0),
- IDWALK_NEVER_SELF = (1 << 1),
+ IDWALK_CB_NOP = 0,
+ IDWALK_CB_NEVER_NULL = (1 << 0),
+ IDWALK_CB_NEVER_SELF = (1 << 1),
/**
* Indicates whether this is direct (i.e. by local data) or indirect (i.e. by linked data) usage.
* \note Object proxies are half-local, half-linked...
*/
- IDWALK_INDIRECT_USAGE = (1 << 2),
+ IDWALK_CB_INDIRECT_USAGE = (1 << 2),
+
+ /** That ID is used as mere sub-data by its owner
+ * (only case currently: those f***ing nodetrees in materials etc.).
+ * This means callback shall not *do* anything, only use this as informative data if it needs it. */
+ IDWALK_CB_PRIVATE = (1 << 3),
+
+ /** That ID is not really used by its owner, it's just an internal hint/helper.
+ * This addresses Their Highest Ugliness the 'from' pointers: Object->from_proxy and Key->from.
+ * How to handle that kind of cases totally depends on what caller code is doing... */
+ IDWALK_CB_LOOPBACK = (1 << 4),
/**
* Adjusts #ID.us reference-count.
* \note keep in sync with 'newlibadr_us' use in readfile.c
*/
- IDWALK_USER = (1 << 8),
- /**
- * Ensure #ID.us is at least 1 on use.
- */
- IDWALK_USER_ONE = (1 << 9),
+ IDWALK_CB_USER = (1 << 8),
+ /** Ensure #ID.us is at least 1 on use. */
+ IDWALK_CB_USER_ONE = (1 << 9),
};
enum {
@@ -68,21 +76,25 @@ enum {
*
* \return a set of flags to control further iteration (0 to keep going).
*/
-typedef int (*LibraryIDLinkCallback) (void *user_data, struct ID *id_self, struct ID **id_pointer, int cd_flag);
+typedef int (*LibraryIDLinkCallback) (void *user_data, struct ID *id_self, struct ID **id_pointer, int cb_flag);
/* Flags for the foreach function itself. */
enum {
+ IDWALK_NOP = 0,
IDWALK_READONLY = (1 << 0),
IDWALK_RECURSE = (1 << 1), /* Also implies IDWALK_READONLY. */
+
+ IDWALK_NO_INDIRECT_PROXY_DATA_USAGE = (1 << 8), /* Ugly special case :(((( */
};
/* Loop over all of the ID's this datablock links to. */
-void BKE_library_foreach_ID_link(struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
-void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cd_flag);
+void BKE_library_foreach_ID_link(
+ struct Main *bmain, struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
+void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cb_flag);
int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
-bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used);
+bool BKE_library_id_can_use_idtype(struct ID *id_owner, const short id_type_used);
bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv);
bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv);
diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h
index 89b087014b2..fd37fd762f4 100644
--- a/source/blender/blenkernel/BKE_library_remap.h
+++ b/source/blender/blenkernel/BKE_library_remap.h
@@ -46,6 +46,11 @@ enum {
/* 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 and can cause crashes very easily! */
ID_REMAP_FORCE_NEVER_NULL_USAGE = 1 << 3,
+ /* Do not consider proxy/_group pointers of local objects as indirect usages...
+ * Our oh-so-beloved proxies again... Do not consider data used by local proxy object as indirect usage.
+ * This is needed e.g. in reload scenario, since we have to ensure remapping of Armature data of local proxy
+ * is also performed. Usual nightmare... */
+ ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4,
};
/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */
@@ -64,6 +69,7 @@ void BKE_libblock_relink_ex(
struct Main *bmain, void *idv, void *old_idv, void *new_idv,
const bool us_min_never_null) ATTR_NONNULL(1, 2);
+void BKE_libblock_relink_to_newid(struct ID *id) ATTR_NONNULL();
typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *);
typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index af9bf58ce77..3ba4fbe0338 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -52,7 +52,10 @@ struct bContext;
void BKE_linestyle_init(struct FreestyleLineStyle *linestyle);
FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name);
void BKE_linestyle_free(FreestyleLineStyle *linestyle);
-FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle);
+void BKE_linestyle_copy_data(
+ struct Main *bmain, struct FreestyleLineStyle *linestyle_dst, const struct FreestyleLineStyle *linestyle_src,
+ const int flag);
+FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineStyle *linestyle);
void BKE_linestyle_make_local(struct Main *bmain, struct FreestyleLineStyle *linestyle, const bool lib_local);
@@ -63,10 +66,14 @@ LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyl
LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
-LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
-LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
-LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
-LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
+LineStyleModifier *BKE_linestyle_color_modifier_copy(
+ FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag);
+LineStyleModifier *BKE_linestyle_alpha_modifier_copy(
+ FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag);
+LineStyleModifier *BKE_linestyle_thickness_modifier_copy(
+ FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag);
+LineStyleModifier *BKE_linestyle_geometry_modifier_copy(
+ FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag);
int BKE_linestyle_color_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
int BKE_linestyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index a4f5c425282..387045878f3 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -51,6 +51,8 @@ extern "C" {
struct EvaluationContext;
struct Library;
struct MainLock;
+struct GHash;
+struct BLI_mempool;
/* Blender thumbnail, as written on file (width, height, and data as char RGBA). */
/* We pack pixel data after that struct. */
@@ -59,6 +61,22 @@ typedef struct BlendThumbnail {
char rect[0];
} BlendThumbnail;
+/* Structs caching relations between data-blocks in a given Main. */
+typedef struct MainIDRelationsEntry {
+ struct MainIDRelationsEntry *next;
+ /* WARNING! for user_to_used, that pointer is really an ID** one, but for used_to_user, it’s only an ID* one! */
+ struct ID **id_pointer;
+ int usage_flag; /* Using IDWALK_ enums, in BKE_library_query.h */
+} MainIDRelationsEntry;
+
+typedef struct MainIDRelations {
+ struct GHash *id_user_to_used;
+ struct GHash *id_used_to_user;
+
+ /* Private... */
+ struct BLI_mempool *entry_pool;
+} MainIDRelations;
+
typedef struct Main {
struct Main *next, *prev;
char name[1024]; /* 1024 = FILE_MAX */
@@ -111,6 +129,11 @@ typedef struct Main {
/* Evaluation context used by viewport */
struct EvaluationContext *eval_ctx;
+ /* Must be generated, used and freed by same code - never assume this is valid data unless you know
+ * when, who and how it was created.
+ * Used by code doing a lot of remapping etc. at once to speed things up. */
+ struct MainIDRelations *relations;
+
struct MainLock *lock;
} Main;
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 3349bffac85..5598f0dc473 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -32,6 +32,7 @@
* \ingroup bke
*/
+struct EvaluationContext;
struct ImageUser;
struct Image;
struct ListBase;
@@ -77,14 +78,14 @@ void BKE_mask_layer_free(struct MaskLayer *masklay);
void BKE_mask_layer_free_list(struct ListBase *masklayers);
void BKE_mask_spline_free(struct MaskSpline *spline);
void BKE_mask_spline_free_list(struct ListBase *splines);
-struct MaskSpline *BKE_mask_spline_copy(struct MaskSpline *spline);
+struct MaskSpline *BKE_mask_spline_copy(const struct MaskSpline *spline);
void BKE_mask_point_free(struct MaskSplinePoint *point);
void BKE_mask_layer_unique_name(struct Mask *mask, struct MaskLayer *masklay);
void BKE_mask_layer_rename(struct Mask *mask, struct MaskLayer *masklay, char *oldname, char *newname);
-struct MaskLayer *BKE_mask_layer_copy(struct MaskLayer *layer);
-void BKE_mask_layer_copy_list(struct ListBase *masklayers_new, struct ListBase *masklayers);
+struct MaskLayer *BKE_mask_layer_copy(const struct MaskLayer *layer);
+void BKE_mask_layer_copy_list(struct ListBase *masklayers_new, const struct ListBase *masklayers);
/* splines */
struct MaskSpline *BKE_mask_spline_add(struct MaskLayer *masklay);
@@ -122,8 +123,9 @@ void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const eMask
/* general */
struct Mask *BKE_mask_new(struct Main *bmain, const char *name);
+void BKE_mask_copy_data(struct Main *bmain, struct Mask *mask_dst, const struct Mask *mask_src, const int flag);
struct Mask *BKE_mask_copy_nolib(struct Mask *mask);
-struct Mask *BKE_mask_copy(struct Main *bmain, struct Mask *mask);
+struct Mask *BKE_mask_copy(struct Main *bmain, const struct Mask *mask);
void BKE_mask_make_local(struct Main *bmain, struct Mask *mask, const bool lib_local);
@@ -232,6 +234,12 @@ float *BKE_mask_point_segment_feather_diff(struct MaskSpline *spline, struct Mas
int width, int height,
unsigned int *tot_feather_point);
+void BKE_mask_layer_evaluate_animation(struct MaskLayer *masklay, const float ctime);
+void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, const float ctime);
+
+void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, struct Mask *mask);
+void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, struct Mask *mask);
+
/* mask_rasterize.c */
struct MaskRasterHandle;
typedef struct MaskRasterHandle MaskRasterHandle;
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 8ae5c2b3c45..c6ebda2c399 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -54,7 +54,8 @@ void BKE_material_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
-struct Material *BKE_material_copy(struct Main *bmain, struct Material *ma);
+void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag);
+struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma);
struct Material *localize_material(struct Material *ma);
struct Material *give_node_material(struct Material *ma); /* returns node material or self */
void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local);
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 64320a20281..f02704ba903 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -41,7 +41,8 @@ struct MetaElem;
void BKE_mball_free(struct MetaBall *mb);
void BKE_mball_init(struct MetaBall *mb);
struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name);
-struct MetaBall *BKE_mball_copy(struct Main *bmain, struct MetaBall *mb);
+void BKE_mball_copy_data(struct Main *bmain, struct MetaBall *mb_dst, const struct MetaBall *mb_src, const int flag);
+struct MetaBall *BKE_mball_copy(struct Main *bmain, const struct MetaBall *mb);
void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb, const bool lib_local);
@@ -59,7 +60,7 @@ bool BKE_mball_minmax_ex(struct MetaBall *mb, float min[3], float max[3],
float obmat[4][4], const short flag);
bool BKE_mball_center_median(struct MetaBall *mb, float r_cent[3]);
bool BKE_mball_center_bounds(struct MetaBall *mb, float r_cent[3]);
-void BKE_mball_transform(struct MetaBall *mb, float mat[4][4]);
+void BKE_mball_transform(struct MetaBall *mb, float mat[4][4], const bool do_props);
void BKE_mball_translate(struct MetaBall *mb, const float offset[3]);
struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index d41878825bb..f3b2b653e3d 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -87,7 +87,8 @@ int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
void BKE_mesh_free(struct Mesh *me);
void BKE_mesh_init(struct Mesh *me);
struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
-struct Mesh *BKE_mesh_copy(struct Main *bmain, struct Mesh *me);
+void BKE_mesh_copy_data(struct Main *bmain, struct Mesh *me_dst, const struct Mesh *me_src, const int flag);
+struct Mesh *BKE_mesh_copy(struct Main *bmain, const struct Mesh *me);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
@@ -110,7 +111,8 @@ int BKE_mesh_nurbs_displist_to_mdata(
struct MEdge **r_alledge, int *r_totedge,
struct MLoop **r_allloop, struct MPoly **r_allpoly,
struct MLoopUV **r_alluv, int *r_totloop, int *r_totpoly);
-void BKE_mesh_from_nurbs_displist(struct Object *ob, struct ListBase *dispbase, const bool use_orco_uv);
+void BKE_mesh_from_nurbs_displist(
+ struct Object *ob, struct ListBase *dispbase, const bool use_orco_uv, const char *obdata_name);
void BKE_mesh_from_nurbs(struct Object *ob);
void BKE_mesh_to_curve_nurblist(struct DerivedMesh *dm, struct ListBase *nurblist, const int edge_users_test);
void BKE_mesh_to_curve(struct Scene *scene, struct Object *ob);
@@ -131,8 +133,7 @@ bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const cha
float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3];
-void BKE_mesh_calc_normals_split(struct Mesh *mesh);
-void BKE_mesh_split_faces(struct Mesh *mesh);
+void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Scene *sce, struct Object *ob,
int apply_modifiers, int settings, int calc_tessface, int calc_undeformed);
@@ -228,6 +229,9 @@ void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, const float
bool BKE_mesh_has_custom_loop_normals(struct Mesh *me);
+void BKE_mesh_calc_normals_split(struct Mesh *mesh);
+void BKE_mesh_calc_normals_split_ex(struct Mesh *mesh, struct MLoopNorSpaceArray *r_lnors_spacearr);
+
void BKE_mesh_normals_loop_split(
const struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges,
struct MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
@@ -276,7 +280,8 @@ void BKE_mesh_poly_edgebitmap_insert(
bool BKE_mesh_center_median(const struct Mesh *me, float r_cent[3]);
bool BKE_mesh_center_bounds(const struct Mesh *me, float r_cent[3]);
-bool BKE_mesh_center_centroid(const struct Mesh *me, float r_cent[3]);
+bool BKE_mesh_center_of_surface(const struct Mesh *me, float r_cent[3]);
+bool BKE_mesh_center_of_volume(const struct Mesh *me, float r_cent[3]);
void BKE_mesh_calc_volume(
const struct MVert *mverts, const int mverts_num,
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index f6c08909d23..30c47a4b192 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -106,8 +106,8 @@ typedef enum {
} ModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
-typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cd_flag);
-typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cd_flag);
+typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
+typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
typedef void (*TexWalkFunc)(void *userData, struct Object *ob, struct ModifierData *md, const char *propname);
typedef enum ModifierApplyFlag {
@@ -273,7 +273,7 @@ typedef struct ModifierTypeInfo {
*
* This function is optional.
*/
- /* TODO(sergey): Remove once we finalyl switched to the new depsgraph. */
+ /* TODO(sergey): Remove once we finally switched to the new depsgraph. */
void (*updateDepsgraph)(struct ModifierData *md,
struct Main *bmain,
struct Scene *scene,
@@ -344,6 +344,7 @@ bool modifier_unique_name(struct ListBase *modifiers, struct ModifierDa
void modifier_copyData_generic(const struct ModifierData *md, struct ModifierData *target);
void modifier_copyData(struct ModifierData *md, struct ModifierData *target);
+void modifier_copyData_ex(struct ModifierData *md, struct ModifierData *target, const int flag);
bool modifier_dependsOnTime(struct ModifierData *md);
bool modifier_supportsMapping(struct ModifierData *md);
bool modifier_supportsCage(struct Scene *scene, struct ModifierData *md);
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index 3237c146bc5..3ddf75f204e 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -41,7 +41,8 @@ struct MovieDistortion;
void BKE_movieclip_free(struct MovieClip *clip);
-struct MovieClip *BKE_movieclip_copy(struct Main *bmain, struct MovieClip *clip);
+void BKE_movieclip_copy_data(struct Main *bmain, struct MovieClip *clip_dst, const struct MovieClip *clip_src, const int flag);
+struct MovieClip *BKE_movieclip_copy(struct Main *bmain, const struct MovieClip *clip);
void BKE_movieclip_make_local(struct Main *bmain, struct MovieClip *clip, const bool lib_local);
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 95f06e9f695..81de70ca8a4 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -49,7 +49,7 @@
#include "RNA_types.h"
/* not very important, but the stack solver likes to know a maximum */
-#define MAX_SOCKET 64
+#define MAX_SOCKET 512
struct bContext;
struct bNode;
@@ -335,10 +335,9 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char
/* copy/free funcs, need to manage ID users */
void ntreeFreeTree(struct bNodeTree *ntree);
-struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user);
-struct bNodeTree *ntreeCopyTree(struct Main *bmain, struct bNodeTree *ntree);
-void ntreeSwitchID_ex(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to, const bool do_id_user);
-void ntreeSwitchID(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to);
+void BKE_node_tree_copy_data(struct Main *bmain, struct bNodeTree *ntree_dst, const struct bNodeTree *ntree_src, const int flag);
+struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user);
+struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree);
/* node->id user count */
void ntreeUserIncrefID(struct bNodeTree *ntree);
void ntreeUserDecrefID(struct bNodeTree *ntree);
@@ -454,6 +453,7 @@ void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node);
void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node);
void nodeFreeNode(struct bNodeTree *ntree, struct bNode *node);
+struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree, struct bNode *node_src, const int flag);
struct bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node);
struct bNodeLink *nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock);
@@ -787,6 +787,7 @@ struct ShadeResult;
#define SH_NODE_OUTPUT_LINESTYLE 190
#define SH_NODE_UVALONGSTROKE 191
#define SH_NODE_TEX_POINTDENSITY 192
+#define SH_NODE_BSDF_PRINCIPLED 193
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
@@ -974,7 +975,8 @@ void ntreeCompositExecTree(struct Scene *scene, struct bNodeTree *ntree, struct
void ntreeCompositTagRender(struct Scene *sce);
int ntreeCompositTagAnimated(struct bNodeTree *ntree);
void ntreeCompositTagGenerators(struct bNodeTree *ntree);
-void ntreeCompositForceHidden(struct bNodeTree *ntree);
+void ntreeCompositUpdateRLayers(struct bNodeTree *ntree);
+void ntreeCompositRegisterPass(struct bNodeTree *ntree, struct Scene *scene, struct SceneRenderLayer *srl, const char *name, int type);
void ntreeCompositClearTags(struct bNodeTree *ntree);
struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree, struct bNode *node,
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index cf07a178fe8..d1a4033957b 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -53,10 +53,10 @@ void BKE_object_workob_clear(struct Object *workob);
void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struct Object *workob);
void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src);
-struct SoftBody *copy_softbody(const struct SoftBody *sb, bool copy_caches);
-struct BulletSoftBody *copy_bulletsoftbody(struct BulletSoftBody *sb);
-struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys);
-void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src);
+struct SoftBody *copy_softbody(const struct SoftBody *sb, const int flag);
+struct BulletSoftBody *copy_bulletsoftbody(const struct BulletSoftBody *sb, const int flag);
+struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys, const int flag);
+void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src, const int flag);
void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_particlesystems(struct Object *ob);
void BKE_object_free_softbody(struct Object *ob);
@@ -105,8 +105,8 @@ bool BKE_object_lod_is_usable(struct Object *ob, struct Scene *scene);
struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct Scene *scene);
struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene);
-struct Object *BKE_object_copy_ex(struct Main *bmain, struct Object *ob, bool copy_caches);
-struct Object *BKE_object_copy(struct Main *bmain, struct Object *ob);
+void BKE_object_copy_data(struct Main *bmain, struct Object *ob_dst, const struct Object *ob_src, const int flag);
+struct Object *BKE_object_copy(struct Main *bmain, const struct Object *ob);
void BKE_object_make_local(struct Main *bmain, struct Object *ob, const bool lib_local);
void BKE_object_make_local_ex(struct Main *bmain, struct Object *ob, const bool lib_local, const bool clear_proxy);
bool BKE_object_is_libdata(struct Object *ob);
@@ -136,16 +136,9 @@ void BKE_object_where_is_calc_mat4(struct Scene *scene, struct Object *ob, float
/* possibly belong in own moduke? */
struct BoundBox *BKE_boundbox_alloc_unit(void);
void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3]);
-bool BKE_boundbox_ray_hit_check(
- const struct BoundBox *bb,
- const float ray_start[3], const float ray_normal[3],
- float *r_lambda);
void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3]);
void BKE_boundbox_calc_size_aabb(const struct BoundBox *bb, float r_size[3]);
void BKE_boundbox_minmax(const struct BoundBox *bb, float obmat[4][4], float r_min[3], float r_max[3]);
-void BKE_boundbox_scale(struct BoundBox *bb_dst, const struct BoundBox *bb_src, float scale);
-struct BoundBox *BKE_boundbox_ensure_minimum_dimensions(
- struct BoundBox *bb, struct BoundBox *bb_temp, const float epsilon);
struct BoundBox *BKE_object_boundbox_get(struct Object *ob);
void BKE_object_dimensions_get(struct Object *ob, float vec[3]);
@@ -196,10 +189,6 @@ void BKE_object_eval_constraints(struct EvaluationContext *eval_ctx,
struct Object *ob);
void BKE_object_eval_done(struct EvaluationContext *eval_ctx, struct Object *ob);
-void BKE_object_eval_modifier(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- struct ModifierData *md);
void BKE_object_eval_uber_transform(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
@@ -207,6 +196,11 @@ void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
+void BKE_object_eval_cloth(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *object);
+
+
void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 0a3cc950f32..3a70819ec58 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -99,7 +99,9 @@ void BKE_paint_set_overlay_override(enum OverlayFlags flag);
/* palettes */
void BKE_palette_free(struct Palette *palette);
struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
-struct Palette *BKE_palette_copy(struct Main *bmain, struct Palette *palette);
+void BKE_palette_copy_data(
+ struct Main *bmain, struct Palette *palette_dst, const struct Palette *palette_src, const int flag);
+struct Palette *BKE_palette_copy(struct Main *bmain, const struct Palette *palette);
void BKE_palette_make_local(struct Main *bmain, struct Palette *palette, const bool lib_local);
struct PaletteColor *BKE_palette_color_add(struct Palette *palette);
bool BKE_palette_is_empty(const struct Palette *palette);
@@ -109,12 +111,14 @@ void BKE_palette_clear(struct Palette *palette);
/* paint curves */
struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
void BKE_paint_curve_free(struct PaintCurve *pc);
-struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, struct PaintCurve *pc);
+void BKE_paint_curve_copy_data(
+ struct Main *bmain, struct PaintCurve *pc_dst, const struct PaintCurve *pc_src, const int flag);
+struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, const struct PaintCurve *pc);
void BKE_paint_curve_make_local(struct Main *bmain, struct PaintCurve *pc, const bool lib_local);
void BKE_paint_init(struct Scene *sce, PaintMode mode, const char col[3]);
void BKE_paint_free(struct Paint *p);
-void BKE_paint_copy(struct Paint *src, struct Paint *tar);
+void BKE_paint_copy(struct Paint *src, struct Paint *tar, const int flag);
void BKE_paint_cavity_curve_preset(struct Paint *p, int preset);
@@ -156,6 +160,14 @@ void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct B
void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);
+/* Used for both vertex color and weight paint */
+struct SculptVertexPaintGeomMap {
+ int *vert_map_mem;
+ struct MeshElemMap *vert_to_loop;
+ int *poly_map_mem;
+ struct MeshElemMap *vert_to_poly;
+};
+
/* Session data (mode-specific) */
typedef struct SculptSession {
@@ -201,10 +213,38 @@ typedef struct SculptSession {
struct SculptStroke *stroke;
struct StrokeCache *cache;
+
+ union {
+ struct {
+ struct SculptVertexPaintGeomMap gmap;
+
+ /* For non-airbrush painting to re-apply from the original (MLoop aligned). */
+ unsigned int *previous_color;
+ } vpaint;
+
+ struct {
+ struct SculptVertexPaintGeomMap gmap;
+ /* Keep track of how much each vertex has been painted (non-airbrush only). */
+ float *alpha_weight;
+
+ /* Needed to continuously re-apply over the same weights (BRUSH_ACCUMULATE disabled).
+ * Lazy initialize as needed (flag is set to 1 to tag it as uninitialized). */
+ struct MDeformVert *dvert_prev;
+ } wpaint;
+
+ //struct {
+ //ToDo: identify sculpt-only fields
+ //} sculpt;
+ } mode;
+ int mode_type;
+
+ /* This flag prevents PBVH from being freed when creating the vp_handle for texture paint. */
+ bool building_vp_handle;
} SculptSession;
void BKE_sculptsession_free(struct Object *ob);
void BKE_sculptsession_free_deformMats(struct SculptSession *ss);
+void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
void BKE_sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob,
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index b3e3968ca9b..ddb4f9c37bd 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -207,7 +207,7 @@ typedef struct ParticleCollisionElement {
typedef struct ParticleCollision {
struct Object *current;
struct Object *hit;
- struct Object *skip[PARTICLE_COLLISION_MAX_COLLISIONS+1];
+ struct Object *skip[PARTICLE_COLLISION_MAX_COLLISIONS + 1];
struct Object *emitter;
struct CollisionModifierData *md; // collision modifier for current object;
@@ -324,7 +324,10 @@ struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct P
struct ModifierData *object_add_particle_system(struct Scene *scene, struct Object *ob, const char *name);
void object_remove_particle_system(struct Scene *scene, struct Object *ob);
struct ParticleSettings *psys_new_settings(const char *name, struct Main *main);
-struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain, struct ParticleSettings *part);
+void BKE_particlesettings_copy_data(
+ struct Main *bmain, struct ParticleSettings *part_dst, const struct ParticleSettings *part_src,
+ const int flag);
+struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain, const struct ParticleSettings *part);
void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part, const bool lib_local);
void psys_reset(struct ParticleSystem *psys, int mode);
@@ -384,7 +387,7 @@ void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleDa
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);
+typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cb_flag);
void BKE_particlesystem_id_loop(struct ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata);
@@ -473,9 +476,8 @@ typedef struct ParticleRenderData {
struct EvaluationContext;
-void BKE_particle_system_eval(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- struct ParticleSystem *psys);
+void BKE_particle_system_eval_init(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
#endif
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 927303f8b3c..2daa2ef7182 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -32,6 +32,7 @@
struct CCGElem;
struct CCGKey;
+struct CCGDerivedMesh;
struct CustomData;
struct DMFlagMat;
struct MPoly;
@@ -58,6 +59,8 @@ typedef bool (*BKE_pbvh_SearchCallback)(PBVHNode *node, void *data);
typedef void (*BKE_pbvh_HitCallback)(PBVHNode *node, void *data);
typedef void (*BKE_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *tmin);
+typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float *tmin);
+
/* Building */
PBVH *BKE_pbvh_new(void);
@@ -71,7 +74,7 @@ void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems,
struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset);
-
+void BKE_pbvh_set_ccgdm(PBVH *bvh, struct CCGDerivedMesh *ccgdm);
void BKE_pbvh_free(PBVH *bvh);
void BKE_pbvh_free_layer_disp(PBVH *bvh);
@@ -100,12 +103,12 @@ void BKE_pbvh_raycast(
bool BKE_pbvh_node_raycast(
PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco,
const float ray_start[3], const float ray_normal[3],
- float *dist);
+ float *depth);
bool BKE_pbvh_bmesh_node_raycast_detail(
PBVHNode *node,
const float ray_start[3], const float ray_normal[3],
- float *dist, float *r_detail);
+ float *depth, float *r_detail);
/* for orthographic cameras, project the far away ray segment points to the root node so
* we can have better precision. */
@@ -113,11 +116,22 @@ void BKE_pbvh_raycast_project_ray_root(
PBVH *bvh, bool original,
float ray_start[3], float ray_end[3], float ray_normal[3]);
+void BKE_pbvh_find_nearest_to_ray(
+ PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data,
+ const float ray_start[3], const float ray_normal[3],
+ bool original);
+
+bool BKE_pbvh_node_find_nearest_to_ray(
+ PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco,
+ const float ray_start[3], const float ray_normal[3],
+ float *depth, float *dist_sq);
+
/* Drawing */
void BKE_pbvh_node_draw(PBVHNode *node, void *data);
void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
int (*setMaterial)(int matnr, void *attribs), bool wireframe, bool fast);
+void BKE_pbvh_draw_BB(PBVH *bvh);
/* PBVH Access */
typedef enum {
@@ -141,6 +155,7 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
/* multires level, only valid for type == PBVH_GRIDS */
void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key);
+struct CCGDerivedMesh *BKE_pbvh_get_ccgdm(const PBVH *bvh);
/* Only valid for type == PBVH_BMESH */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
@@ -153,7 +168,7 @@ typedef enum {
bool BKE_pbvh_bmesh_update_topology(
PBVH *bvh, PBVHTopologyUpdateMode mode,
const float center[3], const float view_normal[3],
- float radius);
+ float radius, const bool use_frontface, const bool use_projected);
/* Node Access */
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index 8cab33582fb..a1a8d2df154 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -315,7 +315,7 @@ struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches);
void BKE_ptcache_free_mem(struct ListBase *mem_cache);
void BKE_ptcache_free(struct PointCache *cache);
void BKE_ptcache_free_list(struct ListBase *ptcaches);
-struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, bool copy_data);
+struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, const int flag);
/********************** Baking *********************/
diff --git a/source/blender/blenkernel/BKE_property.h b/source/blender/blenkernel/BKE_property.h
index 99e60757f15..c787e8e8ed1 100644
--- a/source/blender/blenkernel/BKE_property.h
+++ b/source/blender/blenkernel/BKE_property.h
@@ -37,8 +37,8 @@ struct Object;
void BKE_bproperty_free(struct bProperty *prop);
void BKE_bproperty_free_list(struct ListBase *lb);
-struct bProperty *BKE_bproperty_copy(struct bProperty *prop);
-void BKE_bproperty_copy_list(struct ListBase *lbn, struct ListBase *lbo);
+struct bProperty *BKE_bproperty_copy(const struct bProperty *prop);
+void BKE_bproperty_copy_list(struct ListBase *lbn, const struct ListBase *lbo);
void BKE_bproperty_init(struct bProperty *prop);
struct bProperty *BKE_bproperty_new(int type);
void BKE_bproperty_unique(struct bProperty *first, struct bProperty *prop, int force);
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 272abc42899..3c7274ca3c5 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -49,12 +49,11 @@ void BKE_rigidbody_free_constraint(struct Object *ob);
/* ...... */
-struct RigidBodyOb *BKE_rigidbody_copy_object(struct Object *ob);
-struct RigidBodyCon *BKE_rigidbody_copy_constraint(struct Object *ob);
-void BKE_rigidbody_relink_constraint(struct RigidBodyCon *rbc);
+struct RigidBodyOb *BKE_rigidbody_copy_object(const struct Object *ob, const int flag);
+struct RigidBodyCon *BKE_rigidbody_copy_constraint(const struct Object *ob, const int flag);
/* Callback format for performing operations on ID-pointers for rigidbody world. */
-typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, struct ID **idpoin, void *userdata, int cd_flag);
+typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, struct ID **idpoin, void *userdata, int cb_flag);
void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata);
@@ -67,7 +66,7 @@ struct RigidBodyOb *BKE_rigidbody_create_object(struct Scene *scene, struct Obje
struct RigidBodyCon *BKE_rigidbody_create_constraint(struct Scene *scene, struct Object *ob, short type);
/* copy */
-struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw);
+struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw, const int flag);
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw);
/* 'validate' (i.e. make new or replace old) Physics-Engine objects */
diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h
index a504f1bac3d..35bcd91a9b1 100644
--- a/source/blender/blenkernel/BKE_sca.h
+++ b/source/blender/blenkernel/BKE_sca.h
@@ -52,16 +52,16 @@ void free_actuators(struct ListBase *lb);
void free_sensor(struct bSensor *sens);
void free_sensors(struct ListBase *lb);
-struct bSensor *copy_sensor(struct bSensor *sens);
-void copy_sensors(struct ListBase *lbn, struct ListBase *lbo);
+struct bSensor *copy_sensor(struct bSensor *sens, const int flag);
+void copy_sensors(struct ListBase *lbn, const struct ListBase *lbo, const int flag);
void init_sensor(struct bSensor *sens);
struct bSensor *new_sensor(int type);
-struct bController *copy_controller(struct bController *cont);
-void copy_controllers(struct ListBase *lbn, struct ListBase *lbo);
+struct bController *copy_controller(struct bController *cont, const int flag);
+void copy_controllers(struct ListBase *lbn, const struct ListBase *lbo, const int flag);
void init_controller(struct bController *cont);
struct bController *new_controller(int type);
-struct bActuator *copy_actuator(struct bActuator *act);
-void copy_actuators(struct ListBase *lbn, struct ListBase *lbo);
+struct bActuator *copy_actuator(struct bActuator *act, const int flag);
+void copy_actuators(struct ListBase *lbn, const struct ListBase *lbo, const int flag);
void init_actuator(struct bActuator *act);
struct bActuator *new_actuator(int type);
void clear_sca_new_poins_ob(struct Object *ob);
@@ -70,16 +70,16 @@ void set_sca_new_poins_ob(struct Object *ob);
void set_sca_new_poins(void);
void BKE_sca_logic_links_remap(struct Main *bmain, struct Object *ob_old, struct Object *ob_new);
-void BKE_sca_logic_copy(struct Object *ob_new, struct Object *ob);
+void BKE_sca_logic_copy(struct Object *ob_new, const struct Object *ob, const int flag);
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);
void sca_move_actuator(struct bActuator *act_to_move, struct Object *ob, int move_up);
/* Callback format for performing operations on ID-pointers for sensors/controllers/actuators. */
-typedef void (*SCASensorIDFunc)(struct bSensor *sensor, struct ID **idpoin, void *userdata, int cd_flag);
-typedef void (*SCAControllerIDFunc)(struct bController *controller, struct ID **idpoin, void *userdata, int cd_flag);
-typedef void (*SCAActuatorIDFunc)(struct bActuator *actuator, struct ID **idpoin, void *userdata, int cd_flag);
+typedef void (*SCASensorIDFunc)(struct bSensor *sensor, struct ID **idpoin, void *userdata, int cb_flag);
+typedef void (*SCAControllerIDFunc)(struct bController *controller, struct ID **idpoin, void *userdata, int cb_flag);
+typedef void (*SCAActuatorIDFunc)(struct bActuator *actuator, struct ID **idpoin, void *userdata, int cb_flag);
void BKE_sca_sensors_id_loop(struct ListBase *senslist, SCASensorIDFunc func, void *userdata);
void BKE_sca_controllers_id_loop(struct ListBase *contlist, SCAControllerIDFunc func, void *userdata);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index d2152950bff..481aff3cfa6 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -42,7 +42,6 @@ struct Base;
struct EvaluationContext;
struct Main;
struct Object;
-struct QuicktimeCodecData;
struct RenderData;
struct SceneRenderLayer;
struct Scene;
@@ -64,7 +63,6 @@ struct Main;
struct Base *_setlooper_base_step(struct Scene **sce_iter, struct Base *base);
void free_avicodecdata(struct AviCodecData *acd);
-void free_qtcodecdata(struct QuicktimeCodecData *acd);
void BKE_scene_free(struct Scene *sce);
void BKE_scene_init(struct Scene *sce);
@@ -98,6 +96,7 @@ void BKE_scene_base_flag_from_objects(struct Scene *scene);
void BKE_scene_set_background(struct Main *bmain, struct Scene *sce);
struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
+void BKE_scene_copy_data(struct Main *bmain, struct Scene *sce_dst, const struct Scene *sce_src, const int flag);
struct Scene *BKE_scene_copy(struct Main *bmain, struct Scene *sce, int type);
void BKE_scene_groups_relink(struct Scene *sce);
@@ -151,6 +150,8 @@ bool BKE_scene_check_rigidbody_active(const struct Scene *scene);
int BKE_scene_num_threads(const struct Scene *scene);
int BKE_render_num_threads(const struct RenderData *r);
+int BKE_render_preview_pixel_size(const struct RenderData *r);
+
double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value);
/* multiview */
@@ -175,4 +176,3 @@ int BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
#endif
#endif
-
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 811e9136fc9..657e99f05d1 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -335,7 +335,8 @@ bool BKE_sequence_base_shuffle(
bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, struct Scene *evil_scene);
bool BKE_sequence_base_isolated_sel_check(struct ListBase *seqbase);
void BKE_sequencer_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render);
-struct Sequence *BKE_sequence_dupli_recursive(struct Scene *scene, struct Scene *scene_to, struct Sequence *seq, int dupe_flag);
+struct Sequence *BKE_sequence_dupli_recursive(
+ const struct Scene *scene_src, struct Scene *scene_dst, struct Sequence *seq, int dupe_flag);
int BKE_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str);
bool BKE_sequence_check_depend(struct Sequence *seq, struct Sequence *cur);
@@ -352,8 +353,8 @@ void BKE_sequencer_refresh_sound_length(struct Scene *scene);
void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq);
void BKE_sequence_base_dupli_recursive(
- struct Scene *scene, struct Scene *scene_to, ListBase *nseqbase, ListBase *seqbase,
- int dupe_flag);
+ const struct Scene *scene_src, struct Scene *scene_dst, struct ListBase *nseqbase, const struct ListBase *seqbase,
+ int dupe_flag, const int flag);
bool BKE_sequence_is_valid_check(struct Sequence *seq);
void BKE_sequencer_clear_scene_in_allseqs(struct Main *bmain, struct Scene *sce);
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 28b15b2a310..6f8274fabc8 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -80,6 +80,8 @@ void BKE_sound_load(struct Main *main, struct bSound *sound);
void BKE_sound_free(struct bSound *sound);
+void BKE_sound_copy_data(struct Main *bmain, struct bSound *sound_dst, const struct bSound *sound_src, const int flag);
+
void BKE_sound_make_local(struct Main *bmain, struct bSound *sound, const bool lib_local);
#if defined(__AUD_C_API_H__) || defined(WITH_SYSTEM_AUDASPACE)
@@ -90,6 +92,8 @@ void BKE_sound_create_scene(struct Scene *scene);
void BKE_sound_destroy_scene(struct Scene *scene);
+void BKE_sound_reset_scene_specs(struct Scene *scene);
+
void BKE_sound_mute_scene(struct Scene *scene, int muted);
void BKE_sound_update_fps(struct Scene *scene);
diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h
index b91b64c4b74..57f4c37f129 100644
--- a/source/blender/blenkernel/BKE_speaker.h
+++ b/source/blender/blenkernel/BKE_speaker.h
@@ -33,7 +33,8 @@ struct Speaker;
void BKE_speaker_init(struct Speaker *spk);
void *BKE_speaker_add(struct Main *bmain, const char *name);
-struct Speaker *BKE_speaker_copy(struct Main *bmain, struct Speaker *spk);
+void BKE_speaker_copy_data(struct Main *bmain, struct Speaker *spk_dst, const struct Speaker *spk_src, const int flag);
+struct Speaker *BKE_speaker_copy(struct Main *bmain, const struct Speaker *spk);
void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk, const bool lib_local);
void BKE_speaker_free(struct Speaker *spk);
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index 081b7589af6..14d3318e059 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -52,7 +52,8 @@ bool BKE_text_reload(struct Text *text);
struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const char *relpath,
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_copy_data(struct Main *bmain, struct Text *ta_dst, const struct Text *ta_src, const int flag);
+struct Text *BKE_text_copy (struct Main *bmain, const struct Text *ta);
void BKE_text_make_local (struct Main *bmain, struct Text *text, const bool lib_local);
void BKE_text_clear (struct Text *text);
void BKE_text_write (struct Text *text, const char *str);
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 1c5ea946f59..8a9171673ea 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -42,6 +42,7 @@ struct Brush;
struct ColorBand;
struct EnvMap;
struct FreestyleLineStyle;
+struct ImagePool;
struct Lamp;
struct Main;
struct Material;
@@ -69,7 +70,8 @@ void colorband_update_sort(struct ColorBand *coba);
void BKE_texture_free(struct Tex *tex);
void BKE_texture_default(struct Tex *tex);
-struct Tex *BKE_texture_copy(struct Main *bmain, struct Tex *tex);
+void BKE_texture_copy_data(struct Main *bmain, struct Tex *tex_dst, const struct Tex *tex_src, const int flag);
+struct Tex *BKE_texture_copy(struct Main *bmain, const struct Tex *tex);
struct Tex *BKE_texture_add(struct Main *bmain, const char *name);
struct Tex *BKE_texture_localize(struct Tex *tex);
void BKE_texture_make_local(struct Main *bmain, struct Tex *tex, const bool lib_local);
@@ -113,13 +115,13 @@ void BKE_texture_colormapping_default(struct ColorMapping *color
void BKE_texture_envmap_free_data(struct EnvMap *env);
void BKE_texture_envmap_free(struct EnvMap *env);
struct EnvMap *BKE_texture_envmap_add(void);
-struct EnvMap *BKE_texture_envmap_copy(struct EnvMap *env);
+struct EnvMap *BKE_texture_envmap_copy(const struct EnvMap *env, const int flag);
void BKE_texture_pointdensity_init_data(struct PointDensity *pd);
void BKE_texture_pointdensity_free_data(struct PointDensity *pd);
void BKE_texture_pointdensity_free(struct PointDensity *pd);
struct PointDensity *BKE_texture_pointdensity_add(void);
-struct PointDensity *BKE_texture_pointdensity_copy(struct PointDensity *pd);
+struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, const int flag);
void BKE_texture_voxeldata_free_data(struct VoxelData *vd);
void BKE_texture_voxeldata_free(struct VoxelData *vd);
@@ -128,15 +130,23 @@ struct VoxelData *BKE_texture_voxeldata_copy(struct VoxelData *vd);
void BKE_texture_ocean_free(struct OceanTex *ot);
struct OceanTex *BKE_texture_ocean_add(void);
-struct OceanTex *BKE_texture_ocean_copy(struct OceanTex *ot);
+struct OceanTex *BKE_texture_ocean_copy(const struct OceanTex *ot, const int flag);
bool BKE_texture_dependsOnTime(const struct Tex *texture);
bool BKE_texture_is_image_user(const struct Tex *tex);
+void BKE_texture_get_value_ex(
+ const struct Scene *scene, struct Tex *texture,
+ float *tex_co, struct TexResult *texres,
+ struct ImagePool *pool,
+ bool use_color_management);
+
void BKE_texture_get_value(
const struct Scene *scene, struct Tex *texture,
float *tex_co, struct TexResult *texres, bool use_color_management);
+void BKE_texture_fetch_images_for_pool(struct Tex *texture, struct ImagePool *pool);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 30873567297..d05ed1800fb 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -52,7 +52,7 @@ struct rcti;
/* **** Common functions **** */
void BKE_tracking_free(struct MovieTracking *tracking);
-void BKE_tracking_copy(struct MovieTracking *tracking_dst, struct MovieTracking *tracking_src);
+void BKE_tracking_copy(struct MovieTracking *tracking_dst, const struct MovieTracking *tracking_src, const int flag);
void BKE_tracking_settings_init(struct MovieTracking *tracking);
diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h
index 23bf9ec3d22..2a811496bb9 100644
--- a/source/blender/blenkernel/BKE_world.h
+++ b/source/blender/blenkernel/BKE_world.h
@@ -39,7 +39,8 @@ struct World;
void BKE_world_free(struct World *sc);
void BKE_world_init(struct World *wrld);
struct World *add_world(struct Main *bmian, const char *name);
-struct World *BKE_world_copy(struct Main *bmain, struct World *wrld);
+void BKE_world_copy_data(struct Main *bmain, struct World *wrld_dst, const struct World *wrld_src, const int flag);
+struct World *BKE_world_copy(struct Main *bmain, const struct World *wrld);
struct World *localize_world(struct World *wrld);
void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 157c4408d6a..51598ede862 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -385,16 +385,6 @@ if(WITH_CODEC_AVI)
add_definitions(-DWITH_AVI)
endif()
-if(WITH_CODEC_QUICKTIME)
- list(APPEND INC
- ../quicktime
- )
- list(APPEND INC_SYS
- ${QUICKTIME_INCLUDE_DIRS}
- )
- add_definitions(-DWITH_QUICKTIME)
-endif()
-
if(WITH_CODEC_FFMPEG)
list(APPEND SRC
intern/writeffmpeg.c
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index ae18f5289d4..9dae4c5eae7 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -93,6 +93,10 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
# define ASSERT_IS_VALID_DM(dm)
#endif
+
+static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+
static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob);
static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid);
@@ -230,7 +234,33 @@ static MPoly *dm_dupPolyArray(DerivedMesh *dm)
static int dm_getNumLoopTri(DerivedMesh *dm)
{
- return dm->looptris.num;
+ const int numlooptris = poly_to_tri_count(dm->getNumPolys(dm), dm->getNumLoops(dm));
+ BLI_assert(ELEM(dm->looptris.num, 0, numlooptris));
+ return numlooptris;
+}
+
+static const MLoopTri *dm_getLoopTriArray(DerivedMesh *dm)
+{
+ MLoopTri *looptri;
+
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ);
+ looptri = dm->looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
+
+ if (looptri != NULL) {
+ BLI_assert(dm->getNumLoopTri(dm) == dm->looptris.num);
+ }
+ else {
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE);
+ /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already
+ * recomputed those looptris. */
+ if (dm->looptris.array == NULL) {
+ dm->recalcLoopTri(dm);
+ }
+ looptri = dm->looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
+ }
+ return looptri;
}
static CustomData *dm_getVertCData(DerivedMesh *dm)
@@ -276,6 +306,8 @@ void DM_init_funcs(DerivedMesh *dm)
dm->dupLoopArray = dm_dupLoopArray;
dm->dupPolyArray = dm_dupPolyArray;
+ dm->getLoopTriArray = dm_getLoopTriArray;
+
/* subtypes handle getting actual data */
dm->getNumLoopTri = dm_getNumLoopTri;
@@ -469,6 +501,8 @@ void DM_ensure_tessface(DerivedMesh *dm)
/**
* Ensure the array is large enough
+ *
+ * /note This function must always be thread-protected by caller. It should only be used by internal code.
*/
void DM_ensure_looptri_data(DerivedMesh *dm)
{
@@ -476,18 +510,22 @@ void DM_ensure_looptri_data(DerivedMesh *dm)
const unsigned int totloop = dm->numLoopData;
const int looptris_num = poly_to_tri_count(totpoly, totloop);
+ BLI_assert(dm->looptris.array_wip == NULL);
+
+ SWAP(MLoopTri *, dm->looptris.array, dm->looptris.array_wip);
+
if ((looptris_num > dm->looptris.num_alloc) ||
(looptris_num < dm->looptris.num_alloc * 2) ||
(totpoly == 0))
{
- MEM_SAFE_FREE(dm->looptris.array);
+ MEM_SAFE_FREE(dm->looptris.array_wip);
dm->looptris.num_alloc = 0;
dm->looptris.num = 0;
}
if (totpoly) {
- if (dm->looptris.array == NULL) {
- dm->looptris.array = MEM_mallocN(sizeof(*dm->looptris.array) * looptris_num, __func__);
+ if (dm->looptris.array_wip == NULL) {
+ dm->looptris.array_wip = MEM_mallocN(sizeof(*dm->looptris.array_wip) * looptris_num, __func__);
dm->looptris.num_alloc = looptris_num;
}
@@ -495,19 +533,6 @@ void DM_ensure_looptri_data(DerivedMesh *dm)
}
}
-/**
- * The purpose of this function is that we can call:
- * `dm->getLoopTriArray(dm)` and get the array returned.
- */
-void DM_ensure_looptri(DerivedMesh *dm)
-{
- const int numPolys = dm->getNumPolys(dm);
-
- if ((dm->looptris.num == 0) && (numPolys != 0)) {
- dm->recalcLoopTri(dm);
- }
-}
-
void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num)
{
int i;
@@ -2121,6 +2146,8 @@ static void mesh_calc_modifiers(
DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
append_mask |= CD_MASK_PREVIEW_MLOOPCOL;
}
+
+ dm->deformedOnly = false;
}
isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
@@ -2197,7 +2224,6 @@ static void mesh_calc_modifiers(
if (dataMask & CD_MASK_MFACE) {
DM_ensure_tessface(finaldm);
}
- DM_ensure_looptri(finaldm);
/* without this, drawing ngon tri's faces will show ugly tessellated face
* normals and will also have to calculate normals on the fly, try avoid
@@ -2213,6 +2239,12 @@ static void mesh_calc_modifiers(
}
}
+ /* Some modifiers, like datatransfer, may generate those data as temp layer, we do not want to keep them,
+ * as they are used by display code when available (i.e. even if autosmooth is disabled). */
+ if (!do_loop_normals && CustomData_has_layer(&finaldm->loopData, CD_NORMAL)) {
+ CustomData_free_layers(&finaldm->loopData, CD_NORMAL, finaldm->numLoopData);
+ }
+
#ifdef WITH_GAMEENGINE
/* NavMesh - this is a hack but saves having a NavMesh modifier */
if ((ob->gameflag & OB_NAVMESH) && (finaldm->type == DM_TYPE_CDDM)) {
@@ -2455,6 +2487,8 @@ static void editbmesh_calc_modifiers(
deformedVerts = NULL;
}
}
+
+ dm->deformedOnly = false;
}
/* In case of active preview modifier, make sure preview mask remains for following modifiers. */
@@ -2548,6 +2582,15 @@ static void editbmesh_calc_modifiers(
/* same as mesh_calc_modifiers (if using loop normals, poly nors have already been computed). */
if (!do_loop_normals) {
dm_ensure_display_normals(*r_final);
+
+ /* Some modifiers, like datatransfer, may generate those data, we do not want to keep them,
+ * as they are used by display code when available (i.e. even if autosmooth is disabled). */
+ if (CustomData_has_layer(&(*r_final)->loopData, CD_NORMAL)) {
+ CustomData_free_layers(&(*r_final)->loopData, CD_NORMAL, (*r_final)->numLoopData);
+ }
+ if (r_cage && CustomData_has_layer(&(*r_cage)->loopData, CD_NORMAL)) {
+ CustomData_free_layers(&(*r_cage)->loopData, CD_NORMAL, (*r_cage)->numLoopData);
+ }
}
/* add an orco layer if needed */
@@ -2620,7 +2663,7 @@ static void mesh_build_data(
ob->lastDataMask = dataMask;
ob->lastNeedMapping = need_mapping;
- if ((ob->mode & OB_MODE_SCULPT) && ob->sculpt) {
+ if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
/* create PBVH immediately (would be created on the fly too,
* but this avoids waiting on first stroke) */
@@ -2895,9 +2938,6 @@ DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em, CustomDa
/* get derived mesh from an object, using editbmesh if available. */
DerivedMesh *object_get_derived_final(Object *ob, const bool for_render)
{
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_btmesh;
-
if (for_render) {
/* TODO(sergey): use proper derived render here in the future. */
return ob->derivedFinal;
@@ -2905,9 +2945,13 @@ DerivedMesh *object_get_derived_final(Object *ob, const bool for_render)
/* only return the editmesh if its from this object because
* we don't a mesh from another object's modifier stack: T43122 */
- if (em && (em->ob == ob)) {
- DerivedMesh *dm = em->derivedFinal;
- return dm;
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ if (em && (em->ob == ob)) {
+ DerivedMesh *dm = em->derivedFinal;
+ return dm;
+ }
}
return ob->derivedFinal;
@@ -3300,7 +3344,8 @@ void DM_calc_loop_tangents_step_0(
const CustomData *loopData, bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME], int tangent_names_count,
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
- char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
+ char *ract_uv_name, char *rren_uv_name, short *rtangent_mask)
+{
/* Active uv in viewport */
int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
*ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
@@ -3354,21 +3399,22 @@ void DM_calc_loop_tangents_step_0(
if (add)
*rtangent_mask |= 1 << n;
}
+
+ if (uv_layer_num == 0)
+ *rtangent_mask |= DM_TANGENT_MASK_ORCO;
}
void DM_calc_loop_tangents(
DerivedMesh *dm, bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME], int tangent_names_count)
{
- if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV) == 0)
- return;
int act_uv_n = -1;
int ren_uv_n = -1;
bool calc_act = false;
bool calc_ren = false;
char act_uv_name[MAX_NAME];
char ren_uv_name[MAX_NAME];
- char tangent_mask = 0;
+ short tangent_mask = 0;
DM_calc_loop_tangents_step_0(
&dm->loopData, calc_active_tangent, tangent_names, tangent_names_count,
&calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
@@ -3381,6 +3427,8 @@ void DM_calc_loop_tangents(
for (int i = 0; i < tangent_names_count; i++)
if (tangent_names[i][0])
DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, tangent_names[i]);
+ if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, "") == -1)
+ CustomData_add_layer_named(&dm->loopData, CD_TANGENT, CD_CALLOC, NULL, dm->numLoopData, "");
if (calc_act && act_uv_name[0])
DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, act_uv_name);
if (calc_ren && ren_uv_name[0])
@@ -3438,23 +3486,28 @@ void DM_calc_loop_tangents(
* have to check this is valid...
*/
mesh2tangent->precomputedLoopNormals = dm->getLoopDataArray(dm, CD_NORMAL);
- mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->faceData, CD_NORMAL);
+ mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->polyData, CD_NORMAL);
mesh2tangent->orco = NULL;
mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
+
+ /* Fill the resulting tangent_mask */
if (!mesh2tangent->mloopuv) {
mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
if (!mesh2tangent->orco)
continue;
+
+ dm->tangent_mask |= DM_TANGENT_MASK_ORCO;
+ }
+ else {
+ int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
+ int uv_start = CustomData_get_layer_index(&dm->loopData, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ dm->tangent_mask |= 1 << (uv_ind - uv_start);
}
- mesh2tangent->tangent = dm->loopData.layers[index].data;
- /* Fill the resulting tangent_mask */
- int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
- int uv_start = CustomData_get_layer_index(&dm->loopData, CD_MLOOPUV);
- BLI_assert(uv_ind != -1 && uv_start != -1);
- BLI_assert(uv_ind - uv_start < MAX_MTFACE);
- dm->tangent_mask |= 1 << (uv_ind - uv_start);
+ mesh2tangent->tangent = dm->loopData.layers[index].data;
BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
}
@@ -3470,21 +3523,19 @@ void DM_calc_loop_tangents(
#endif
- int uv_index, tan_index;
-
/* Update active layer index */
- uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
- if (uv_index != -1) {
- tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
+ int act_uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
+ if (act_uv_index != -1) {
+ int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[act_uv_index].name);
CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
- }
+ } /* else tangent has been built from orco */
/* Update render layer index */
- uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n);
- if (uv_index != -1) {
- tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
+ int ren_uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n);
+ if (ren_uv_index != -1) {
+ int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[ren_uv_index].name);
CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
- }
+ } /* else tangent has been built from orco */
}
}
@@ -4357,35 +4408,3 @@ MFace *DM_get_tessface_array(DerivedMesh *dm, bool *r_allocated)
return mface;
}
-
-const MLoopTri *DM_get_looptri_array(
- DerivedMesh *dm,
- const MVert *mvert,
- const MPoly *mpoly, int mpoly_len,
- const MLoop *mloop, int mloop_len,
- bool *r_allocated)
-{
- const MLoopTri *looptri = dm->getLoopTriArray(dm);
- *r_allocated = false;
-
- if (looptri == NULL) {
- if (mpoly_len > 0) {
- const int looptris_num = poly_to_tri_count(mpoly_len, mloop_len);
- MLoopTri *looptri_data;
-
- looptri_data = MEM_mallocN(sizeof(MLoopTri) * looptris_num, __func__);
-
- BKE_mesh_recalc_looptri(
- mloop, mpoly,
- mvert,
- mloop_len, mpoly_len,
- looptri_data);
-
- looptri = looptri_data;
-
- *r_allocated = true;
- }
- }
-
- return looptri;
-}
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index dcbb667adca..5bd6085c8f5 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -44,6 +44,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -87,7 +88,7 @@ bAction *add_empty_action(Main *bmain, const char name[])
{
bAction *act;
- act = BKE_libblock_alloc(bmain, ID_AC, name);
+ act = BKE_libblock_alloc(bmain, ID_AC, name, 0);
return act;
}
@@ -119,46 +120,56 @@ void BKE_action_free(bAction *act)
/* .................................. */
-bAction *BKE_action_copy(Main *bmain, bAction *src)
+/**
+ * Only copy internal data of Action ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_action_copy_data(Main *UNUSED(bmain), bAction *act_dst, const bAction *act_src, const int UNUSED(flag))
{
- bAction *dst = NULL;
- bActionGroup *dgrp, *sgrp;
- FCurve *dfcu, *sfcu;
-
- if (src == NULL)
- return NULL;
- dst = BKE_libblock_copy(bmain, &src->id);
-
+ bActionGroup *grp_dst, *grp_src;
+ FCurve *fcu_dst, *fcu_src;
+
/* duplicate the lists of groups and markers */
- BLI_duplicatelist(&dst->groups, &src->groups);
- BLI_duplicatelist(&dst->markers, &src->markers);
-
+ BLI_duplicatelist(&act_dst->groups, &act_src->groups);
+ BLI_duplicatelist(&act_dst->markers, &act_src->markers);
+
/* copy F-Curves, fixing up the links as we go */
- BLI_listbase_clear(&dst->curves);
-
- for (sfcu = src->curves.first; sfcu; sfcu = sfcu->next) {
+ BLI_listbase_clear(&act_dst->curves);
+
+ for (fcu_src = act_src->curves.first; fcu_src; fcu_src = fcu_src->next) {
/* duplicate F-Curve */
- dfcu = copy_fcurve(sfcu);
- BLI_addtail(&dst->curves, dfcu);
-
+ fcu_dst = copy_fcurve(fcu_src); /* XXX TODO pass subdata flag? But surprisingly does not seem to be doing any ID refcounting... */
+ BLI_addtail(&act_dst->curves, fcu_dst);
+
/* fix group links (kindof bad list-in-list search, but this is the most reliable way) */
- for (dgrp = dst->groups.first, sgrp = src->groups.first; dgrp && sgrp; dgrp = dgrp->next, sgrp = sgrp->next) {
- if (sfcu->grp == sgrp) {
- dfcu->grp = dgrp;
-
- if (dgrp->channels.first == sfcu)
- dgrp->channels.first = dfcu;
- if (dgrp->channels.last == sfcu)
- dgrp->channels.last = dfcu;
-
+ for (grp_dst = act_dst->groups.first, grp_src = act_src->groups.first;
+ grp_dst && grp_src;
+ grp_dst = grp_dst->next, grp_src = grp_src->next)
+ {
+ if (fcu_src->grp == grp_src) {
+ fcu_dst->grp = grp_dst;
+
+ if (grp_dst->channels.first == fcu_src) {
+ grp_dst->channels.first = fcu_dst;
+ }
+ if (grp_dst->channels.last == fcu_src) {
+ grp_dst->channels.last = fcu_dst;
+ }
break;
}
}
}
-
- BKE_id_copy_ensure_local(bmain, &src->id, &dst->id);
+}
- return dst;
+bAction *BKE_action_copy(Main *bmain, const bAction *act_src)
+{
+ bAction *act_copy;
+ BKE_id_copy_ex(bmain, &act_src->id, (ID **)&act_copy, 0, false);
+ return act_copy;
}
/* *************** Action Groups *************** */
@@ -494,7 +505,7 @@ bPoseChannel *BKE_pose_channel_get_mirrored(const bPose *pose, const char *name)
{
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, name, false);
+ BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
if (!STREQ(name_flip, name)) {
return BKE_pose_channel_find_name(pose, name_flip);
@@ -522,7 +533,7 @@ const char *BKE_pose_ikparam_get_name(bPose *pose)
*
* \param dst Should be freed already, makes entire duplicate.
*/
-void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
+void BKE_pose_copy_data_ex(bPose **dst, const bPose *src, const int flag, const bool copy_constraints)
{
bPose *outPose;
bPoseChannel *pchan;
@@ -552,9 +563,8 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
outPose->avs = src->avs;
for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) {
-
- if (pchan->custom) {
- id_us_plus(&pchan->custom->id);
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)pchan->custom);
}
/* warning, O(n2) here, if done without the hash, but these are rarely used features. */
@@ -569,13 +579,13 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
}
if (copy_constraints) {
- BKE_constraints_copy(&listb, &pchan->constraints, true); // BKE_constraints_copy NULLs listb
+ BKE_constraints_copy_ex(&listb, &pchan->constraints, flag, true); // BKE_constraints_copy NULLs listb
pchan->constraints = listb;
pchan->mpath = NULL; /* motion paths should not get copied yet... */
}
if (pchan->prop) {
- pchan->prop = IDP_CopyProperty(pchan->prop);
+ pchan->prop = IDP_CopyProperty_ex(pchan->prop, flag);
}
}
@@ -587,6 +597,11 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
*dst = outPose;
}
+void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constraints)
+{
+ BKE_pose_copy_data_ex(dst, src, 0, copy_constraints);
+}
+
void BKE_pose_itasc_init(bItasc *itasc)
{
if (itasc) {
@@ -1114,9 +1129,13 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
if (fcu->totvert) {
float nmin, nmax;
- /* get extents for this curve */
- /* TODO: allow enabling/disabling this? */
- calc_fcurve_range(fcu, &nmin, &nmax, false, true);
+ /* get extents for this curve
+ * - no "selected only", since this is often used in the backend
+ * - no "minimum length" (we will apply this later), otherwise
+ * single-keyframe curves will increase the overall length by
+ * a phantom frame (T50354)
+ */
+ calc_fcurve_range(fcu, &nmin, &nmax, false, false);
/* compare to the running tally */
min = min_ff(min, nmin);
@@ -1169,7 +1188,9 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
}
if (foundvert || foundmod) {
+ /* ensure that action is at least 1 frame long (for NLA strips to have a valid length) */
if (min == max) max += 1.0f;
+
*start = min;
*end = max;
}
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index 7d3d12ac112..2f65e71c6d2 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -201,7 +201,15 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Objec
mpath->flag |= MOTIONPATH_FLAG_BHEAD;
else
mpath->flag &= ~MOTIONPATH_FLAG_BHEAD;
-
+
+ /* set default custom values */
+ mpath->color[0] = 1.0; /* Red */
+ mpath->color[1] = 0.0;
+ mpath->color[2] = 0.0;
+
+ mpath->line_thickness = 1;
+ mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
+
/* allocate a cache */
mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts");
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index a5abc6beff8..64b33326aa9 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -43,6 +43,7 @@
#include "BLI_alloca.h"
#include "BLI_dynstr.h"
#include "BLI_listbase.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -258,7 +259,7 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
/* Copying -------------------------------------------- */
/* Make a copy of the given AnimData - to be used when copying datablocks */
-AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action)
+AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
{
AnimData *dadt;
@@ -269,8 +270,9 @@ AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action)
/* make a copy of action - at worst, user has to delete copies... */
if (do_action) {
- dadt->action = BKE_action_copy(G.main, adt->action);
- dadt->tmpact = BKE_action_copy(G.main, adt->tmpact);
+ BLI_assert(bmain != NULL);
+ BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, 0, false);
+ BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, 0, false);
}
else {
id_us_plus((ID *)dadt->action);
@@ -290,7 +292,7 @@ AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action)
return dadt;
}
-bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action)
+bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const bool do_action)
{
AnimData *adt;
@@ -302,23 +304,25 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action)
adt = BKE_animdata_from_id(id_from);
if (adt) {
IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
- iat->adt = BKE_animdata_copy(adt, do_action);
+ iat->adt = BKE_animdata_copy(bmain, adt, do_action);
}
return true;
}
-void BKE_animdata_copy_id_action(ID *id)
+void BKE_animdata_copy_id_action(ID *id, const bool set_newid)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
if (adt->action) {
id_us_min((ID *)adt->action);
- adt->action = BKE_action_copy(G.main, adt->action);
+ adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(G.main, adt->action)) :
+ BKE_action_copy(G.main, adt->action);
}
if (adt->tmpact) {
id_us_min((ID *)adt->tmpact);
- adt->tmpact = BKE_action_copy(G.main, adt->tmpact);
+ adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(G.main, adt->tmpact)) :
+ BKE_action_copy(G.main, adt->tmpact);
}
}
}
@@ -394,73 +398,6 @@ void BKE_animdata_merge_copy(ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes a
}
}
-/* Make Local -------------------------------------------- */
-
-static void make_local_strips(ListBase *strips)
-{
- NlaStrip *strip;
-
- for (strip = strips->first; strip; strip = strip->next) {
- if (strip->act) BKE_action_make_local(G.main, strip->act, false);
- if (strip->remap && strip->remap->target) BKE_action_make_local(G.main, strip->remap->target, false);
-
- make_local_strips(&strip->strips);
- }
-}
-
-/* Use local copy instead of linked copy of various ID-blocks */
-void BKE_animdata_make_local(AnimData *adt)
-{
- NlaTrack *nlt;
-
- /* Actions - Active and Temp */
- if (adt->action) BKE_action_make_local(G.main, adt->action, false);
- if (adt->tmpact) BKE_action_make_local(G.main, adt->tmpact, false);
- /* Remaps */
- if (adt->remap && adt->remap->target) BKE_action_make_local(G.main, adt->remap->target, false);
-
- /* Drivers */
- /* TODO: need to remap the ID-targets too? */
-
- /* NLA Data */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next)
- make_local_strips(&nlt->strips);
-}
-
-
-/* When duplicating data (i.e. objects), drivers referring to the original data will
- * get updated to point to the duplicated data (if drivers belong to the new data)
- */
-void BKE_animdata_relink(AnimData *adt)
-{
- /* sanity check */
- if (adt == NULL)
- return;
-
- /* drivers */
- if (adt->drivers.first) {
- FCurve *fcu;
-
- /* check each driver against all the base paths to see if any should go */
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
-
- /* driver variables */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* only change the used targets, since the others will need fixing manually anyway */
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- if (dtar->id && dtar->id->newid) {
- dtar->id = dtar->id->newid;
- }
- }
- DRIVER_TARGETS_LOOPER_END
- }
- }
- }
-}
-
/* Sub-ID Regrouping ------------------------------------------- */
/**
@@ -687,6 +624,8 @@ char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *p
}
break;
}
+ default:
+ break;
}
/* fix RNA pointer, as we've now changed the ID root by changing the paths */
@@ -1411,7 +1350,7 @@ void BKE_keyingset_free_path(KeyingSet *ks, KS_Path *ksp)
}
/* Copy all KeyingSets in the given list */
-void BKE_keyingsets_copy(ListBase *newlist, ListBase *list)
+void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list)
{
KeyingSet *ksn;
KS_Path *kspn;
@@ -1583,7 +1522,8 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
}
case PROP_INT:
{
- const int value_coerce = (int)value;
+ int value_coerce = (int)value;
+ RNA_property_int_clamp(ptr, prop, &value_coerce);
if (array_index != -1) {
if (RNA_property_int_get_index(ptr, prop, array_index) != value_coerce) {
RNA_property_int_set_index(ptr, prop, array_index, value_coerce);
@@ -1600,15 +1540,17 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
}
case PROP_FLOAT:
{
+ float value_coerce = value;
+ RNA_property_float_clamp(ptr, prop, &value_coerce);
if (array_index != -1) {
- if (RNA_property_float_get_index(ptr, prop, array_index) != value) {
- RNA_property_float_set_index(ptr, prop, array_index, value);
+ if (RNA_property_float_get_index(ptr, prop, array_index) != value_coerce) {
+ RNA_property_float_set_index(ptr, prop, array_index, value_coerce);
written = true;
}
}
else {
- if (RNA_property_float_get(ptr, prop) != value) {
- RNA_property_float_set(ptr, prop, value);
+ if (RNA_property_float_get(ptr, prop) != value_coerce) {
+ RNA_property_float_set(ptr, prop, value_coerce);
written = true;
}
}
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index b1dcc40279f..6dd852c7875 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -106,7 +106,8 @@ const char *BKE_appdir_folder_default(void)
static char *blender_version_decimal(const int ver)
{
static char version_str[5];
- sprintf(version_str, "%d.%02d", ver / 100, ver % 100);
+ BLI_assert(ver < 1000);
+ BLI_snprintf(version_str, sizeof(version_str), "%d.%02d", ver / 100, ver % 100);
return version_str;
}
@@ -114,18 +115,26 @@ static char *blender_version_decimal(const int ver)
* Concatenates path_base, (optional) path_sep and (optional) folder_name into targetpath,
* returning true if result points to a directory.
*/
-static bool test_path(char *targetpath, const char *path_base, const char *path_sep, const char *folder_name)
+static bool test_path(
+ char *targetpath, size_t targetpath_len,
+ const char *path_base, const char *path_sep, const char *folder_name)
{
char tmppath[FILE_MAX];
- if (path_sep) BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
- else BLI_strncpy(tmppath, path_base, sizeof(tmppath));
-
- /* rare cases folder_name is omitted (when looking for ~/.blender/2.xx dir only) */
- if (folder_name)
- BLI_make_file_string("/", targetpath, tmppath, folder_name);
- else
- BLI_strncpy(targetpath, tmppath, sizeof(tmppath));
+ if (path_sep) {
+ BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
+ }
+ else {
+ BLI_strncpy(tmppath, path_base, sizeof(tmppath));
+ }
+
+ /* rare cases folder_name is omitted (when looking for ~/.config/blender/2.xx dir only) */
+ if (folder_name) {
+ BLI_join_dirfile(targetpath, targetpath_len, tmppath, folder_name);
+ }
+ else {
+ BLI_strncpy(targetpath, tmppath, targetpath_len);
+ }
/* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile)
* if folder_name is specified but not otherwise? */
@@ -179,7 +188,9 @@ static bool test_env_path(char *path, const char *envvar)
* \param ver To construct name of version-specific directory within bprogdir
* \return true if such a directory exists.
*/
-static bool get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver)
+static bool get_path_local(
+ char *targetpath, size_t targetpath_len,
+ const char *folder_name, const char *subfolder_name, const int ver)
{
char relfolder[FILE_MAX];
@@ -201,11 +212,14 @@ static bool get_path_local(char *targetpath, const char *folder_name, const char
/* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
#ifdef __APPLE__
- static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
- sprintf(osx_resourses, "%s../Resources", bprogdir);
- return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder);
+ /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
+ char osx_resourses[FILE_MAX];
+ BLI_snprintf(osx_resourses, sizeof(osx_resourses), "%s../Resources", bprogdir);
+ /* Remove the '/../' added above. */
+ BLI_cleanup_path(NULL, osx_resourses);
+ return test_path(targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder);
#else
- return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder);
+ return test_path(targetpath, targetpath_len, bprogdir, blender_version_decimal(ver), relfolder);
#endif
}
@@ -219,7 +233,7 @@ static bool is_portable_install(void)
const int ver = BLENDER_VERSION;
char path[FILE_MAX];
- return get_path_local(path, "config", NULL, ver);
+ return get_path_local(path, sizeof(path), "config", NULL, ver);
}
/**
@@ -233,20 +247,22 @@ static bool is_portable_install(void)
* \param ver Blender version, used to construct a subdirectory name
* \return true if it was able to construct such a path.
*/
-static bool get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
+static bool get_path_user(
+ char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name,
+ const char *envvar, const int ver)
{
char user_path[FILE_MAX];
const char *user_base_path;
/* for portable install, user path is always local */
- if (is_portable_install())
- return get_path_local(targetpath, folder_name, subfolder_name, ver);
-
+ if (is_portable_install()) {
+ return get_path_local(targetpath, targetpath_len, folder_name, subfolder_name, ver);
+ }
user_path[0] = '\0';
if (test_env_path(user_path, envvar)) {
if (subfolder_name) {
- return test_path(targetpath, user_path, NULL, subfolder_name);
+ return test_path(targetpath, targetpath_len, user_path, NULL, subfolder_name);
}
else {
BLI_strncpy(targetpath, user_path, FILE_MAX);
@@ -266,10 +282,10 @@ static bool get_path_user(char *targetpath, const char *folder_name, const char
#endif
if (subfolder_name) {
- return test_path(targetpath, user_path, folder_name, subfolder_name);
+ return test_path(targetpath, targetpath_len, user_path, folder_name, subfolder_name);
}
else {
- return test_path(targetpath, user_path, NULL, folder_name);
+ return test_path(targetpath, targetpath_len, user_path, NULL, folder_name);
}
}
@@ -283,7 +299,9 @@ static bool get_path_user(char *targetpath, const char *folder_name, const char
* \param ver Blender version, used to construct a subdirectory name
* \return true if it was able to construct such a path.
*/
-static bool get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
+static bool get_path_system(
+ char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name,
+ const char *envvar, const int ver)
{
char system_path[FILE_MAX];
const char *system_base_path;
@@ -307,14 +325,16 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
/* try CWD/release/folder_name */
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
- if (test_path(targetpath, cwd, "release", relfolder)) {
+ if (test_path(targetpath, targetpath_len, cwd, "release", relfolder)) {
return true;
}
}
-
/* try EXECUTABLE_DIR/release/folder_name */
- if (test_path(targetpath, bprogdir, "release", relfolder))
+ if (test_path(targetpath, targetpath_len, bprogdir, "release", relfolder)) {
return true;
+ }
+ /* never use if not existing. */
+ targetpath[0] = '\0';
/* end developer overrides */
@@ -324,7 +344,7 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
if (test_env_path(system_path, envvar)) {
if (subfolder_name) {
- return test_path(targetpath, system_path, NULL, subfolder_name);
+ return test_path(targetpath, targetpath_len, system_path, NULL, subfolder_name);
}
else {
BLI_strncpy(targetpath, system_path, FILE_MAX);
@@ -345,57 +365,63 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
if (subfolder_name) {
/* try $BLENDERPATH/folder_name/subfolder_name */
- return test_path(targetpath, system_path, folder_name, subfolder_name);
+ return test_path(targetpath, targetpath_len, system_path, folder_name, subfolder_name);
}
else {
/* try $BLENDERPATH/folder_name */
- return test_path(targetpath, system_path, NULL, folder_name);
+ return test_path(targetpath, targetpath_len, system_path, NULL, folder_name);
}
}
-/* get a folder out of the 'folder_id' presets for paths */
-/* returns the path if found, NULL string if not */
-const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
+/**
+ * Get a folder out of the 'folder_id' presets for paths.
+ * returns the path if found, NULL string if not
+ *
+ * \param subfolder: The name of a directory to check for,
+ * this may contain path separators but must resolve to a directory, checked with #BLI_is_dir.
+ */
+const char *BKE_appdir_folder_id_ex(
+ const int folder_id, const char *subfolder,
+ char *path, size_t path_len)
{
const int ver = BLENDER_VERSION;
- static char path[FILE_MAX] = "";
-
+
switch (folder_id) {
case BLENDER_DATAFILES: /* general case */
- if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
- if (get_path_local(path, "datafiles", subfolder, ver)) break;
- if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_DATAFILES:
- if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
return NULL;
case BLENDER_SYSTEM_DATAFILES:
- if (get_path_local(path, "datafiles", subfolder, ver)) break;
- if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
+ if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_AUTOSAVE:
- if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_CONFIG:
- if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break;
+ if (get_path_user(path, path_len, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break;
return NULL;
case BLENDER_USER_SCRIPTS:
- if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
+ if (get_path_user(path, path_len, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
return NULL;
case BLENDER_SYSTEM_SCRIPTS:
- if (get_path_local(path, "scripts", subfolder, ver)) break;
- if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break;
+ if (get_path_local(path, path_len, "scripts", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break;
return NULL;
case BLENDER_SYSTEM_PYTHON:
- if (get_path_local(path, "python", subfolder, ver)) break;
- if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break;
+ if (get_path_local(path, path_len, "python", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break;
return NULL;
default:
@@ -406,6 +432,13 @@ const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
return path;
}
+const char *BKE_appdir_folder_id(
+ const int folder_id, const char *subfolder)
+{
+ static char path[FILE_MAX] = "";
+ return BKE_appdir_folder_id_ex(folder_id, subfolder, path, sizeof(path));
+}
+
/**
* Returns the path to a folder in the user area without checking that it actually exists first.
*/
@@ -416,16 +449,16 @@ const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *su
switch (folder_id) {
case BLENDER_USER_DATAFILES:
- get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver);
+ get_path_user(path, sizeof(path), "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver);
break;
case BLENDER_USER_CONFIG:
- get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver);
+ get_path_user(path, sizeof(path), "config", subfolder, "BLENDER_USER_CONFIG", ver);
break;
case BLENDER_USER_AUTOSAVE:
- get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver);
+ get_path_user(path, sizeof(path), "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver);
break;
case BLENDER_USER_SCRIPTS:
- get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver);
+ get_path_user(path, sizeof(path), "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver);
break;
default:
BLI_assert(0);
@@ -469,13 +502,13 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con
bool ok;
switch (folder_id) {
case BLENDER_RESOURCE_PATH_USER:
- ok = get_path_user(path, NULL, NULL, NULL, ver);
+ ok = get_path_user(path, sizeof(path), NULL, NULL, NULL, ver);
break;
case BLENDER_RESOURCE_PATH_LOCAL:
- ok = get_path_local(path, NULL, NULL, ver);
+ ok = get_path_local(path, sizeof(path), NULL, NULL, ver);
break;
case BLENDER_RESOURCE_PATH_SYSTEM:
- ok = get_path_system(path, NULL, NULL, NULL, ver);
+ ok = get_path_system(path, sizeof(path), NULL, NULL, NULL, ver);
break;
default:
path[0] = '\0'; /* in case do_check is false */
@@ -563,6 +596,9 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name)
else {
BLI_path_program_search(fullname, maxlen, name);
}
+ /* Remove "/./" and "/../" so string comparisons can be used on the path. */
+ BLI_cleanup_path(NULL, fullname);
+
#if defined(DEBUG)
if (!STREQ(name, fullname)) {
printf("guessing '%s' == '%s'\n", name, fullname);
@@ -655,6 +691,51 @@ bool BKE_appdir_program_python_search(
return is_found;
}
+/** Keep in sync with `bpy.utils.app_template_paths()` */
+static const char *app_template_directory_search[2] = {
+ "startup" SEP_STR "bl_app_templates_user",
+ "startup" SEP_STR "bl_app_templates_system",
+};
+
+static const int app_template_directory_id[2] = {
+ /* Only 'USER' */
+ BLENDER_USER_SCRIPTS,
+ /* Covers 'LOCAL' & 'SYSTEM'. */
+ BLENDER_SYSTEM_SCRIPTS,
+};
+
+/**
+ * Return true if templates exist
+ */
+bool BKE_appdir_app_template_any(void)
+{
+ char temp_dir[FILE_MAX];
+ for (int i = 0; i < 2; i++) {
+ if (BKE_appdir_folder_id_ex(
+ app_template_directory_id[i], app_template_directory_search[i],
+ temp_dir, sizeof(temp_dir)))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len)
+{
+ for (int i = 0; i < 2; i++) {
+ char subdir[FILE_MAX];
+ BLI_join_dirfile(subdir, sizeof(subdir), app_template_directory_search[i], app_template);
+ if (BKE_appdir_folder_id_ex(
+ app_template_directory_id[i], subdir,
+ path, path_len))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* Gets the temp directory when blender first runs.
* If the default path is not found, use try $TEMP
@@ -713,7 +794,8 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
BLI_add_slash(fullname);
#ifdef WIN32
if (userdir && userdir != fullname) {
- BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
+ /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
+ BLI_strncpy(userdir, fullname, maxlen);
}
#endif
}
@@ -755,7 +837,6 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
void BKE_tempdir_init(char *userdir)
{
where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir);
-;
}
/**
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 2b333941c6e..669344e18d7 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -83,10 +83,11 @@ bArmature *BKE_armature_add(Main *bmain, const char *name)
{
bArmature *arm;
- arm = BKE_libblock_alloc(bmain, ID_AR, name);
+ arm = BKE_libblock_alloc(bmain, ID_AR, name, 0);
arm->deformflag = ARM_DEF_VGROUP | ARM_DEF_ENVELOPE;
arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */
arm->layer = 1;
+ arm->ghostsize = 1;
return arm;
}
@@ -149,54 +150,70 @@ void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local)
BKE_id_make_local_generic(bmain, &arm->id, true, lib_local);
}
-static void copy_bonechildren(Bone *newBone, Bone *oldBone, Bone *actBone, Bone **newActBone)
+static void copy_bonechildren(
+ Bone *bone_dst, const Bone *bone_src, const Bone *bone_src_act, Bone **r_bone_dst_act, const int flag)
{
- Bone *curBone, *newChildBone;
+ Bone *bone_src_child, *bone_dst_child;
- if (oldBone == actBone)
- *newActBone = newBone;
+ if (bone_src == bone_src_act) {
+ *r_bone_dst_act = bone_dst;
+ }
- if (oldBone->prop)
- newBone->prop = IDP_CopyProperty(oldBone->prop);
+ if (bone_src->prop) {
+ bone_dst->prop = IDP_CopyProperty_ex(bone_src->prop, flag);
+ }
/* Copy this bone's list */
- BLI_duplicatelist(&newBone->childbase, &oldBone->childbase);
+ BLI_duplicatelist(&bone_dst->childbase, &bone_src->childbase);
/* For each child in the list, update it's children */
- newChildBone = newBone->childbase.first;
- for (curBone = oldBone->childbase.first; curBone; curBone = curBone->next) {
- newChildBone->parent = newBone;
- copy_bonechildren(newChildBone, curBone, actBone, newActBone);
- newChildBone = newChildBone->next;
+ for (bone_src_child = bone_src->childbase.first, bone_dst_child = bone_dst->childbase.first;
+ bone_src_child;
+ bone_src_child = bone_src_child->next, bone_dst_child = bone_dst_child->next)
+ {
+ bone_dst_child->parent = bone_dst;
+ copy_bonechildren(bone_dst_child, bone_src_child, bone_src_act, r_bone_dst_act, flag);
}
}
-bArmature *BKE_armature_copy(Main *bmain, bArmature *arm)
+/**
+ * Only copy internal data of Armature ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_armature_copy_data(Main *UNUSED(bmain), bArmature *arm_dst, const bArmature *arm_src, const int flag)
{
- bArmature *newArm;
- Bone *oldBone, *newBone;
- Bone *newActBone = NULL;
+ Bone *bone_src, *bone_dst;
+ Bone *bone_dst_act = NULL;
- newArm = BKE_libblock_copy(bmain, &arm->id);
- BLI_duplicatelist(&newArm->bonebase, &arm->bonebase);
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+
+ BLI_duplicatelist(&arm_dst->bonebase, &arm_src->bonebase);
/* Duplicate the childrens' lists */
- newBone = newArm->bonebase.first;
- for (oldBone = arm->bonebase.first; oldBone; oldBone = oldBone->next) {
- newBone->parent = NULL;
- copy_bonechildren(newBone, oldBone, arm->act_bone, &newActBone);
- newBone = newBone->next;
+ bone_dst = arm_dst->bonebase.first;
+ for (bone_src = arm_src->bonebase.first; bone_src; bone_src = bone_src->next) {
+ bone_dst->parent = NULL;
+ copy_bonechildren(bone_dst, bone_src, arm_src->act_bone, &bone_dst_act, flag_subdata);
+ bone_dst = bone_dst->next;
}
- newArm->act_bone = newActBone;
-
- newArm->edbo = NULL;
- newArm->act_edbone = NULL;
- newArm->sketch = NULL;
+ arm_dst->act_bone = bone_dst_act;
- BKE_id_copy_ensure_local(bmain, &arm->id, &newArm->id);
+ arm_dst->edbo = NULL;
+ arm_dst->act_edbone = NULL;
+ arm_dst->sketch = NULL;
+}
- return newArm;
+bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm)
+{
+ bArmature *arm_copy;
+ BKE_id_copy_ex(bmain, &arm->id, (ID **)&arm_copy, 0, false);
+ return arm_copy;
}
static Bone *get_named_bone_bonechildren(ListBase *lb, const char *name)
@@ -981,6 +998,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
return;
}
+ if ((armOb->pose->flag & POSE_RECALC) != 0) {
+ printf("ERROR! Trying to evaluate influence of armature '%s' which needs Pose recalc!", armOb->id.name);
+ BLI_assert(0);
+ }
+
invert_m4_m4(obinv, target->obmat);
copy_m4_m4(premat, target->obmat);
mul_m4_m4m4(postmat, obinv, armOb->obmat);
@@ -1036,6 +1058,17 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
if (use_dverts) {
defnrToPC = MEM_callocN(sizeof(*defnrToPC) * defbase_tot, "defnrToBone");
defnrToPCIndex = MEM_callocN(sizeof(*defnrToPCIndex) * defbase_tot, "defnrToIndex");
+ /* TODO(sergey): Some considerations here:
+ *
+ * - Make it more generic function, maybe even keep together with chanhash.
+ * - Check whether keeping this consistent across frames gives speedup.
+ * - Don't use hash for small armatures.
+ */
+ GHash *idx_hash = BLI_ghash_ptr_new("pose channel index by name");
+ int pchan_index = 0;
+ for (pchan = armOb->pose->chanbase.first; pchan != NULL; pchan = pchan->next, ++pchan_index) {
+ BLI_ghash_insert(idx_hash, pchan, SET_INT_IN_POINTER(pchan_index));
+ }
for (i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) {
defnrToPC[i] = BKE_pose_channel_find_name(armOb->pose, dg->name);
/* exclude non-deforming bones */
@@ -1044,10 +1077,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
defnrToPC[i] = NULL;
}
else {
- defnrToPCIndex[i] = BLI_findindex(&armOb->pose->chanbase, defnrToPC[i]);
+ defnrToPCIndex[i] = GET_INT_FROM_POINTER(BLI_ghash_lookup(idx_hash, defnrToPC[i]));
}
}
}
+ BLI_ghash_free(idx_hash, NULL, NULL);
}
}
}
@@ -1967,6 +2001,8 @@ void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones)
if (counter > 1 && sort_bones) {
DAG_pose_sort(ob);
}
+#else
+ UNUSED_VARS(sort_bones);
#endif
ob->pose->flag &= ~POSE_RECALC;
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 3bc81a69c86..45d1d36aeca 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -559,11 +559,10 @@ void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_roo
/* *************** Depsgraph evaluation callbacks ************ */
void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
- Scene *scene,
+ Scene *UNUSED(scene),
Object *ob,
bPose *pose)
{
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bPoseChannel *pchan;
DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
@@ -581,6 +580,16 @@ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
for (pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
}
+}
+
+void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPose *UNUSED(pose))
+{
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
/* 2a. construct the IK tree (standard IK) */
BIK_initialize_tree(scene, ob, ctime);
@@ -628,10 +637,10 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
}
void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
Object *ob,
bPoseChannel *pchan)
{
- Scene *scene = G.main->scene.first;
DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
@@ -702,4 +711,8 @@ void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
ob->id.name + 2, ob->proxy_from->id.name + 2);
}
+ /* Rest of operations are NO-OP in depsgraph, so can clear
+ * flag now.
+ */
+ ob->recalc &= ~OB_RECALC_ALL;
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index a8670395fc4..2624019e63a 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -100,6 +100,18 @@ void BKE_blender_free(void)
free_nodesystem();
}
+void BKE_blender_version_string(char *version_str, size_t maxncpy, short version, short subversion, bool v_prefix, bool include_subversion)
+{
+ const char *prefix = v_prefix ? "v" : "";
+
+ if (include_subversion && subversion > 0) {
+ BLI_snprintf(version_str, maxncpy, "%s%d.%02d.%d", prefix, version / 100, version % 100, subversion);
+ }
+ else {
+ BLI_snprintf(version_str, maxncpy, "%s%d.%02d", prefix, version / 100, version % 100);
+ }
+}
+
void BKE_blender_globals_init(void)
{
memset(&G, 0, sizeof(Global));
@@ -110,10 +122,7 @@ void BKE_blender_globals_init(void)
strcpy(G.ima, "//");
- if (BLENDER_SUBVERSION)
- BLI_snprintf(versionstr, sizeof(versionstr), "v%d.%02d.%d", BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION);
- else
- BLI_snprintf(versionstr, sizeof(versionstr), "v%d.%02d", BLENDER_VERSION / 100, BLENDER_VERSION % 100);
+ BKE_blender_version_string(versionstr, sizeof(versionstr), BLENDER_VERSION, BLENDER_SUBVERSION, true, true);
#ifndef WITH_PYTHON_SECURITY /* default */
G.f |= G_SCRIPT_AUTOEXEC;
@@ -141,20 +150,18 @@ static void keymap_item_free(wmKeyMapItem *kmi)
MEM_freeN(kmi->ptr);
}
-/**
- * When loading a new userdef from file,
- * or when exiting Blender.
- */
-void BKE_blender_userdef_free(void)
+void BKE_blender_userdef_set_data(UserDef *userdef)
{
- wmKeyMap *km;
- wmKeyMapItem *kmi;
- wmKeyMapDiffItem *kmdi;
- bAddon *addon, *addon_next;
- uiFont *font;
-
- for (km = U.user_keymaps.first; km; km = km->next) {
- for (kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
+ /* only here free userdef themes... */
+ BKE_blender_userdef_free_data(&U);
+ U = *userdef;
+}
+
+static void userdef_free_keymaps(UserDef *userdef)
+{
+ for (wmKeyMap *km = userdef->user_keymaps.first, *km_next; km; km = km_next) {
+ km_next = km->next;
+ for (wmKeyMapDiffItem *kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
if (kmdi->add_item) {
keymap_item_free(kmdi->add_item);
MEM_freeN(kmdi->add_item);
@@ -165,14 +172,21 @@ void BKE_blender_userdef_free(void)
}
}
- for (kmi = km->items.first; kmi; kmi = kmi->next)
+ for (wmKeyMapItem *kmi = km->items.first; kmi; kmi = kmi->next) {
keymap_item_free(kmi);
+ }
BLI_freelistN(&km->diff_items);
BLI_freelistN(&km->items);
+
+ MEM_freeN(km);
}
-
- for (addon = U.addons.first; addon; addon = addon_next) {
+ BLI_listbase_clear(&userdef->user_keymaps);
+}
+
+static void userdef_free_addons(UserDef *userdef)
+{
+ for (bAddon *addon = userdef->addons.first, *addon_next; addon; addon = addon_next) {
addon_next = addon->next;
if (addon->prop) {
IDP_FreeProperty(addon->prop);
@@ -180,32 +194,73 @@ void BKE_blender_userdef_free(void)
}
MEM_freeN(addon);
}
+ BLI_listbase_clear(&userdef->addons);
+}
+
+/**
+ * When loading a new userdef from file,
+ * or when exiting Blender.
+ */
+void BKE_blender_userdef_free_data(UserDef *userdef)
+{
+#define U _invalid_access_ /* ensure no accidental global access */
+#ifdef U /* quiet warning */
+#endif
- for (font = U.uifonts.first; font; font = font->next) {
+ userdef_free_keymaps(userdef);
+ userdef_free_addons(userdef);
+
+ for (uiFont *font = userdef->uifonts.first; font; font = font->next) {
BLF_unload_id(font->blf_id);
}
BLF_default_set(-1);
- BLI_freelistN(&U.autoexec_paths);
+ BLI_freelistN(&userdef->autoexec_paths);
+
+ BLI_freelistN(&userdef->uistyles);
+ BLI_freelistN(&userdef->uifonts);
+ BLI_freelistN(&userdef->themes);
- BLI_freelistN(&U.uistyles);
- BLI_freelistN(&U.uifonts);
- BLI_freelistN(&U.themes);
- BLI_freelistN(&U.user_keymaps);
+#undef U
}
/**
- * Handle changes in settings that need refreshing.
+ * Write U from userdef.
+ * This function defines which settings a template will override for the user preferences.
*/
-void BKE_blender_userdef_refresh(void)
+void BKE_blender_userdef_set_app_template(UserDef *userdef)
{
- /* prevent accidents */
- if (U.pixelsize == 0) U.pixelsize = 1;
-
- BLF_default_dpi(U.pixelsize * U.dpi);
- U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72;
+ /* TODO:
+ * - keymaps
+ * - various minor settings (add as needed).
+ */
+
+#define LIST_OVERRIDE(id) { \
+ BLI_freelistN(&U.id); \
+ BLI_movelisttolist(&U.id, &userdef->id); \
+} ((void)0)
+
+#define MEMCPY_OVERRIDE(id) \
+ memcpy(U.id, userdef->id, sizeof(U.id));
+
+ /* for some types we need custom free functions */
+ userdef_free_addons(&U);
+ userdef_free_keymaps(&U);
+
+ LIST_OVERRIDE(uistyles);
+ LIST_OVERRIDE(uifonts);
+ LIST_OVERRIDE(themes);
+ LIST_OVERRIDE(addons);
+ LIST_OVERRIDE(user_keymaps);
+
+ MEMCPY_OVERRIDE(light);
+
+ MEMCPY_OVERRIDE(font_path_ui);
+ MEMCPY_OVERRIDE(font_path_ui_mono);
+#undef LIST_OVERRIDE
+#undef MEMCPY_OVERRIDE
}
/* ***************** testing for break ************* */
@@ -234,7 +289,7 @@ int BKE_blender_test_break(void)
* \note Don't use MEM_mallocN so functions can be registered at any time.
* \{ */
-struct AtExitData {
+static struct AtExitData {
struct AtExitData *next;
void (*func)(void *user_data);
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index bc98d6f6805..e3a5edb2049 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -108,9 +108,9 @@ static int read_undosave(bContext *C, UndoElem *uel)
G.fileflags |= G_FILE_NO_UI;
if (UNDO_DISK)
- success = (BKE_blendfile_read(C, uel->str, NULL) != BKE_BLENDFILE_READ_FAIL);
+ success = (BKE_blendfile_read(C, uel->str, NULL, 0) != BKE_BLENDFILE_READ_FAIL);
else
- success = BKE_blendfile_read_from_memfile(C, &uel->memfile, NULL);
+ success = BKE_blendfile_read_from_memfile(C, &uel->memfile, NULL, 0);
/* restore */
BLI_strncpy(G.main->name, mainstr, sizeof(G.main->name)); /* restore */
@@ -389,7 +389,7 @@ bool BKE_undo_save_file(const char *filename)
Main *BKE_undo_get_main(Scene **r_scene)
{
Main *mainp = NULL;
- BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL);
+ BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL, BLO_READ_SKIP_NONE);
if (bfd) {
mainp = bfd->main;
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 54f709a1e5b..980df05aca2 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -114,6 +114,7 @@ static void setup_app_data(
const char *filepath, ReportList *reports)
{
Scene *curscene = NULL;
+ const bool is_startup = (bfd->filename[0] == '\0');
const bool recover = (G.fileflags & G_FILE_RECOVER) != 0;
enum {
LOAD_UI = 1,
@@ -129,7 +130,7 @@ static void setup_app_data(
else if (BLI_listbase_is_empty(&bfd->main->screen)) {
mode = LOAD_UNDO;
}
- else if (G.fileflags & G_FILE_NO_UI) {
+ else if ((G.fileflags & G_FILE_NO_UI) && (is_startup == false)) {
mode = LOAD_UI_OFF;
}
else {
@@ -227,7 +228,7 @@ static void setup_app_data(
if (bfd->user) {
/* only here free userdef themes... */
- BKE_blender_userdef_free();
+ BKE_blender_userdef_free_data(&U);
U = *bfd->user;
@@ -250,7 +251,9 @@ static void setup_app_data(
CTX_data_scene_set(C, curscene);
}
else {
- G.fileflags = bfd->fileflags;
+ /* Keep state from preferences. */
+ const int fileflags_skip = G_FILE_FLAGS_RUNTIME;
+ G.fileflags = (G.fileflags & fileflags_skip) | (bfd->fileflags & ~fileflags_skip);
CTX_wm_manager_set(C, G.main->wm.first);
CTX_wm_screen_set(C, bfd->curscreen);
CTX_data_scene_set(C, bfd->curscene);
@@ -349,17 +352,23 @@ static int handle_subversion_warning(Main *main, ReportList *reports)
return 1;
}
-int BKE_blendfile_read(bContext *C, const char *filepath, ReportList *reports)
+int BKE_blendfile_read(
+ bContext *C, const char *filepath,
+ ReportList *reports, int skip_flags)
{
BlendFileData *bfd;
int retval = BKE_BLENDFILE_READ_OK;
- if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) /* don't print user-pref loading */
- printf("read blend: %s\n", filepath);
+ /* don't print user-pref loading */
+ if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) {
+ printf("Read blend: %s\n", filepath);
+ }
- bfd = BLO_read_from_file(filepath, reports);
+ bfd = BLO_read_from_file(filepath, reports, skip_flags);
if (bfd) {
- if (bfd->user) retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+ if (bfd->user) {
+ retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+ }
if (0 == handle_subversion_warning(bfd->main, reports)) {
BKE_main_free(bfd->main);
@@ -379,11 +388,11 @@ int BKE_blendfile_read(bContext *C, const char *filepath, ReportList *reports)
bool BKE_blendfile_read_from_memory(
bContext *C, const void *filebuf, int filelength,
- ReportList *reports, bool update_defaults)
+ ReportList *reports, int skip_flags, bool update_defaults)
{
BlendFileData *bfd;
- bfd = BLO_read_from_memory(filebuf, filelength, reports);
+ bfd = BLO_read_from_memory(filebuf, filelength, reports, skip_flags);
if (bfd) {
if (update_defaults)
BLO_update_defaults_startup_blend(bfd->main);
@@ -399,17 +408,17 @@ bool BKE_blendfile_read_from_memory(
/* memfile is the undo buffer */
bool BKE_blendfile_read_from_memfile(
bContext *C, struct MemFile *memfile,
- ReportList *reports)
+ ReportList *reports, int skip_flags)
{
BlendFileData *bfd;
- bfd = BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports);
+ bfd = BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports, skip_flags);
if (bfd) {
/* remove the unused screens and wm */
while (bfd->main->wm.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true, true);
+ BKE_libblock_free(bfd->main, bfd->main->wm.first);
while (bfd->main->screen.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true, true);
+ BKE_libblock_free(bfd->main, bfd->main->screen.first);
setup_app_data(C, bfd, "<memory1>", reports);
}
@@ -420,32 +429,76 @@ bool BKE_blendfile_read_from_memfile(
return (bfd != NULL);
}
+/**
+ * Utility to make a file 'empty' used for startup to optionally give an empty file.
+ * Handy for tests.
+ */
+void BKE_blendfile_read_make_empty(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a;
+
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ id = lbarray[a]->first;
+ if (id != NULL) {
+ if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM)) {
+ continue;
+ }
+ while ((id = lbarray[a]->first)) {
+ BKE_libblock_delete(bmain, id);
+ }
+ }
+ }
+}
+
/* only read the userdef from a .blend */
-int BKE_blendfile_read_userdef(const char *filepath, ReportList *reports)
+UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
{
BlendFileData *bfd;
- int retval = BKE_BLENDFILE_READ_FAIL;
+ UserDef *userdef = NULL;
- bfd = BLO_read_from_file(filepath, reports);
+ bfd = BLO_read_from_file(filepath, reports, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF);
if (bfd) {
if (bfd->user) {
- retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+ userdef = bfd->user;
+ }
+ BKE_main_free(bfd->main);
+ MEM_freeN(bfd);
+ }
- /* only here free userdef themes... */
- BKE_blender_userdef_free();
+ return userdef;
+}
- U = *bfd->user;
- MEM_freeN(bfd->user);
+
+UserDef *BKE_blendfile_userdef_read_from_memory(
+ const void *filebuf, int filelength,
+ ReportList *reports)
+{
+ BlendFileData *bfd;
+ UserDef *userdef = NULL;
+
+ bfd = BLO_read_from_memory(filebuf, filelength, reports, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF);
+ if (bfd) {
+ if (bfd->user) {
+ userdef = bfd->user;
}
BKE_main_free(bfd->main);
MEM_freeN(bfd);
}
+ else {
+ BKE_reports_prepend(reports, "Loading failed: ");
+ }
- return retval;
+ return userdef;
}
+
/* only write the userdef in a .blend */
-int BKE_blendfile_write_userdef(const char *filepath, ReportList *reports)
+int BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
{
Main *mainb = MEM_callocN(sizeof(Main), "empty main");
int retval = 0;
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index b4bc83bf94c..7ca4e07076d 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -1581,7 +1581,7 @@ void boid_free_settings(BoidSettings *boids)
MEM_freeN(boids);
}
}
-BoidSettings *boid_copy_settings(BoidSettings *boids)
+BoidSettings *boid_copy_settings(const BoidSettings *boids)
{
BoidSettings *nboids = NULL;
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 487b8ffa2b5..f210c6aa7f3 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -243,7 +243,7 @@ static bool missing_files_find__recursive(
continue; /* cant stat, don't bother with this file, could print debug info here */
if (S_ISREG(status.st_mode)) { /* is file */
- if (STREQLEN(filename, de->d_name, FILE_MAX)) { /* name matches */
+ if (BLI_path_ncmp(filename, de->d_name, FILE_MAX) == 0) { /* name matches */
/* open the file to read its size */
size = status.st_size;
if ((size > 0) && (size > *r_filesize)) { /* find the biggest file */
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 8ef1fae1155..aeaead578a1 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -152,7 +152,7 @@ Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode)
{
Brush *brush;
- brush = BKE_libblock_alloc(bmain, ID_BR, name);
+ brush = BKE_libblock_alloc(bmain, ID_BR, name, 0);
BKE_brush_init(brush);
@@ -172,34 +172,38 @@ struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode)
return NULL;
}
-Brush *BKE_brush_copy(Main *bmain, Brush *brush)
+/**
+ * Only copy internal data of Brush ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_brush_copy_data(Main *UNUSED(bmain), Brush *brush_dst, const Brush *brush_src, const int flag)
{
- Brush *brushn;
-
- brushn = BKE_libblock_copy(bmain, &brush->id);
-
- if (brush->mtex.tex)
- id_us_plus((ID *)brush->mtex.tex);
-
- if (brush->mask_mtex.tex)
- id_us_plus((ID *)brush->mask_mtex.tex);
-
- if (brush->paint_curve)
- id_us_plus((ID *)brush->paint_curve);
-
- if (brush->icon_imbuf)
- brushn->icon_imbuf = IMB_dupImBuf(brush->icon_imbuf);
+ if (brush_src->icon_imbuf) {
+ brush_dst->icon_imbuf = IMB_dupImBuf(brush_src->icon_imbuf);
+ }
- brushn->preview = NULL;
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&brush_dst->id, &brush_src->id);
+ }
+ else {
+ brush_dst->preview = NULL;
+ }
- brushn->curve = curvemapping_copy(brush->curve);
+ brush_dst->curve = curvemapping_copy(brush_src->curve);
/* enable fake user by default */
- id_fake_user_set(&brush->id);
-
- BKE_id_copy_ensure_local(bmain, &brush->id, &brushn->id);
+ id_fake_user_set(&brush_dst->id);
+}
- return brushn;
+Brush *BKE_brush_copy(Main *bmain, const Brush *brush)
+{
+ Brush *brush_copy;
+ BKE_id_copy_ex(bmain, &brush->id, (ID **)&brush_copy, 0, false);
+ return brush_copy;
}
/** Free (or release) any data used by this brush (does not free the brush itself). */
@@ -239,7 +243,7 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
if (lib_local || is_local) {
if (!is_lib) {
id_clear_lib_data(bmain, &brush->id);
- BKE_id_expand_local(&brush->id);
+ BKE_id_expand_local(bmain, &brush->id);
/* enable fake user by default */
id_fake_user_set(&brush->id);
@@ -249,6 +253,9 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
brush_new->id.us = 0;
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(brush, brush_new);
+
if (!lib_local) {
BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
@@ -514,13 +521,13 @@ int BKE_brush_clone_image_delete(Brush *brush)
* region space mouse coordinates, or 3d world coordinates for 3D mapping.
*
* rgba outputs straight alpha. */
-float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
+float BKE_brush_sample_tex_3D(const Scene *scene, const Brush *br,
const float point[3],
float rgba[4], const int thread,
struct ImagePool *pool)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- MTex *mtex = &br->mtex;
+ const MTex *mtex = &br->mtex;
float intensity = 1.0;
bool hasrgb = false;
@@ -814,7 +821,7 @@ int BKE_brush_size_get(const Scene *scene, const Brush *brush)
return size;
}
-int BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
+bool BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
{
const short us_flag = scene->toolsettings->unified_paint_settings.flag;
@@ -823,7 +830,7 @@ int BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
(brush->flag & BRUSH_LOCK_SIZE);
}
-int BKE_brush_use_size_pressure(const Scene *scene, const Brush *brush)
+bool BKE_brush_use_size_pressure(const Scene *scene, const Brush *brush)
{
const short us_flag = scene->toolsettings->unified_paint_settings.flag;
@@ -832,7 +839,7 @@ int BKE_brush_use_size_pressure(const Scene *scene, const Brush *brush)
(brush->flag & BRUSH_SIZE_PRESSURE);
}
-int BKE_brush_use_alpha_pressure(const Scene *scene, const Brush *brush)
+bool BKE_brush_use_alpha_pressure(const Scene *scene, const Brush *brush)
{
const short us_flag = scene->toolsettings->unified_paint_settings.flag;
@@ -841,6 +848,16 @@ int BKE_brush_use_alpha_pressure(const Scene *scene, const Brush *brush)
(brush->flag & BRUSH_ALPHA_PRESSURE);
}
+bool BKE_brush_sculpt_has_secondary_color(const Brush *brush)
+{
+ return ELEM(
+ brush->sculpt_tool, SCULPT_TOOL_BLOB, SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS,
+ SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE, SCULPT_TOOL_LAYER,
+ SCULPT_TOOL_FLATTEN, SCULPT_TOOL_FILL, SCULPT_TOOL_SCRAPE,
+ SCULPT_TOOL_MASK);
+}
+
void BKE_brush_unprojected_radius_set(Scene *scene, Brush *brush, float unprojected_radius)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -959,7 +976,7 @@ void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask)
}
/* Uses the brush curve control to find a strength value */
-float BKE_brush_curve_strength(Brush *br, float p, const float len)
+float BKE_brush_curve_strength(const Brush *br, float p, const float len)
{
float strength;
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 264d87b86f3..775499304d4 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -393,8 +393,6 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(
BMEditMesh *em, const int verts_num,
const BLI_bitmap *verts_mask, int verts_num_active)
{
- BVHTree *tree = NULL;
- int i;
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
if (verts_mask) {
BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
@@ -403,15 +401,14 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(
verts_num_active = verts_num;
}
- tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+ BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
if (tree) {
- BMIter iter;
- BMVert *eve;
- BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ for (int i = 0; i < verts_num; i++) {
if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
continue;
}
+ BMVert *eve = BM_vert_at_index(em->bm, i);
BLI_bvhtree_insert(tree, i, eve->co, 1);
}
BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
@@ -423,31 +420,28 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(
static BVHTree *bvhtree_from_mesh_verts_create_tree(
float epsilon, int tree_type, int axis,
- MVert *vert, const int verts_num,
+ const MVert *vert, const int verts_num,
const BLI_bitmap *verts_mask, int verts_num_active)
{
- BVHTree *tree = NULL;
- int i;
- if (vert) {
- if (verts_mask) {
- BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
- }
- else {
- verts_num_active = verts_num;
- }
+ BLI_assert(vert != NULL);
+ if (verts_mask) {
+ BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
+ }
+ else {
+ verts_num_active = verts_num;
+ }
- tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+ BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
- if (tree) {
- for (i = 0; i < verts_num; i++) {
- if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
- continue;
- }
- BLI_bvhtree_insert(tree, i, vert[i].co, 1);
+ if (tree) {
+ for (int i = 0; i < verts_num; i++) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
+ continue;
}
- BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
- BLI_bvhtree_balance(tree);
+ BLI_bvhtree_insert(tree, i, vert[i].co, 1);
}
+ BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
+ BLI_bvhtree_balance(tree);
}
return tree;
@@ -455,31 +449,23 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(
static void bvhtree_from_mesh_verts_setup_data(
BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon,
- MVert *vert, const bool vert_allocated)
+ const MVert *vert, const bool vert_allocated)
{
memset(data, 0, sizeof(*data));
- if (tree) {
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- /* a NULL nearest callback works fine
- * remember the min distance to point is the same as the min distance to BV of point */
- data->nearest_callback = NULL;
- data->raycast_callback = mesh_verts_spherecast;
- data->nearest_to_ray_callback = NULL;
+ /* a NULL nearest callback works fine
+ * remember the min distance to point is the same as the min distance to BV of point */
+ data->nearest_callback = NULL;
+ data->raycast_callback = mesh_verts_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */
- data->sphere_radius = epsilon;
- }
- else {
- if (vert_allocated) {
- MEM_freeN(vert);
- }
- }
+ data->sphere_radius = epsilon;
}
/* Builds a bvh tree where nodes are the vertices of the given em */
@@ -488,11 +474,9 @@ BVHTree *bvhtree_from_editmesh_verts_ex(
const BLI_bitmap *verts_mask, int verts_num_active,
float epsilon, int tree_type, int axis)
{
- int vert_num = em->bm->totvert;
-
BVHTree *tree = bvhtree_from_editmesh_verts_create_tree(
epsilon, tree_type, axis,
- em, vert_num, verts_mask, verts_num_active);
+ em, em->bm->totvert, verts_mask, verts_num_active);
if (tree) {
memset(data, 0, sizeof(*data));
@@ -500,11 +484,11 @@ BVHTree *bvhtree_from_editmesh_verts_ex(
data->em = em;
data->nearest_callback = NULL;
data->raycast_callback = editmesh_verts_spherecast;
- data->nearest_to_ray_callback = NULL;
}
return tree;
}
+
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, BMEditMesh *em,
float epsilon, int tree_type, int axis)
@@ -515,8 +499,8 @@ BVHTree *bvhtree_from_editmesh_verts(
epsilon, tree_type, axis);
}
-
-/* Builds a bvh tree where nodes are the vertices of the given dm */
+/* Builds a bvh tree where nodes are the vertices of the given dm
+ * and stores the BVHTree in dm->bvhCache */
BVHTree *bvhtree_from_mesh_verts(
BVHTreeFromMesh *data, DerivedMesh *dm,
float epsilon, int tree_type, int axis)
@@ -556,10 +540,18 @@ BVHTree *bvhtree_from_mesh_verts(
/* printf("BVHTree is already build, using cached tree\n"); */
}
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_verts_setup_data(data, tree, true, epsilon, vert, vert_allocated);
-
- return data->tree;
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_verts_setup_data(
+ data, tree, true, epsilon, vert, vert_allocated);
+ }
+ else {
+ if (vert_allocated) {
+ MEM_freeN(vert);
+ }
+ memset(data, 0, sizeof(*data));
+ }
+ return tree;
}
/**
@@ -569,7 +561,7 @@ BVHTree *bvhtree_from_mesh_verts(
* \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_verts_ex(
- BVHTreeFromMesh *data, MVert *vert, const int verts_num, const bool vert_allocated,
+ BVHTreeFromMesh *data, const MVert *vert, const int verts_num, const bool vert_allocated,
const BLI_bitmap *verts_mask, int verts_num_active,
float epsilon, int tree_type, int axis)
{
@@ -577,9 +569,10 @@ BVHTree *bvhtree_from_mesh_verts_ex(
epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
/* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_verts_setup_data(data, tree, false, epsilon, vert, vert_allocated);
+ bvhtree_from_mesh_verts_setup_data(
+ data, tree, false, epsilon, vert, vert_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -595,8 +588,6 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(
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));
@@ -605,9 +596,10 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(
edges_num_active = edges_num;
}
- tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+ BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
if (tree) {
+ int i;
BMIter iter;
BMEdge *eed;
BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
@@ -627,6 +619,62 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(
return tree;
}
+static BVHTree *bvhtree_from_mesh_edges_create_tree(
+ const MVert *vert, const MEdge *edge, const int edge_num,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ if (edges_mask) {
+ BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
+ }
+ else {
+ edges_num_active = edge_num;
+ }
+ BLI_assert(vert != NULL);
+ BLI_assert(edge != NULL);
+
+ /* Create a bvh-tree of the given target */
+ BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+ if (tree) {
+ for (int i = 0; i < edge_num; i++) {
+ if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
+ continue;
+ }
+ float co[2][3];
+ copy_v3_v3(co[0], vert[edge[i].v1].co);
+ copy_v3_v3(co[1], vert[edge[i].v2].co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 2);
+ }
+ BLI_bvhtree_balance(tree);
+ }
+
+ return tree;
+}
+
+static void bvhtree_from_mesh_edges_setup_data(
+ BVHTreeFromMesh *data, BVHTree *tree,
+ const bool is_cached, float epsilon,
+ const MVert *vert, const bool vert_allocated,
+ const MEdge *edge, const bool edge_allocated)
+{
+ memset(data, 0, sizeof(*data));
+
+ data->tree = tree;
+
+ data->cached = is_cached;
+
+ data->nearest_callback = mesh_edges_nearest_point;
+ data->raycast_callback = mesh_edges_spherecast;
+
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->edge = edge;
+ data->edge_allocated = edge_allocated;
+
+ data->sphere_radius = epsilon;
+}
+
/* Builds a bvh tree where nodes are the edges of the given em */
BVHTree *bvhtree_from_editmesh_edges_ex(
BVHTreeFromEditMesh *data, BMEditMesh *em,
@@ -645,12 +693,11 @@ BVHTree *bvhtree_from_editmesh_edges_ex(
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)
@@ -683,27 +730,13 @@ BVHTree *bvhtree_from_mesh_edges(
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
if (tree == NULL) {
- int i;
- int numEdges = dm->getNumEdges(dm);
-
- if (vert != NULL && edge != NULL) {
- /* Create a bvh-tree of the given target */
- tree = BLI_bvhtree_new(numEdges, epsilon, tree_type, axis);
- if (tree != NULL) {
- for (i = 0; i < numEdges; i++) {
- float co[2][3];
- copy_v3_v3(co[0], vert[edge[i].v1].co);
- copy_v3_v3(co[1], vert[edge[i].v2].co);
-
- BLI_bvhtree_insert(tree, i, co[0], 2);
- }
- BLI_bvhtree_balance(tree);
+ tree = bvhtree_from_mesh_edges_create_tree(
+ vert, edge, dm->getNumEdges(dm),
+ NULL, -1, epsilon, tree_type, axis);
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES);
- }
- }
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
@@ -711,24 +744,10 @@ BVHTree *bvhtree_from_mesh_edges(
/* printf("BVHTree is already build, using cached tree\n"); */
}
-
- /* Setup BVHTreeFromMesh */
- memset(data, 0, sizeof(*data));
- data->tree = tree;
-
- if (data->tree) {
- data->cached = true;
-
- data->nearest_callback = mesh_edges_nearest_point;
- data->raycast_callback = mesh_edges_spherecast;
- data->nearest_to_ray_callback = NULL;
-
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->edge = edge;
- data->edge_allocated = edge_allocated;
-
- data->sphere_radius = epsilon;
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_edges_setup_data(
+ data, tree, true, epsilon, vert, vert_allocated, edge, edge_allocated);
}
else {
if (vert_allocated) {
@@ -737,8 +756,33 @@ BVHTree *bvhtree_from_mesh_edges(
if (edge_allocated) {
MEM_freeN(edge);
}
+ memset(data, 0, sizeof(*data));
}
- return data->tree;
+ return tree;
+}
+
+/**
+ * Builds a bvh tree where nodes are the given edges .
+ * \param vert/edge_allocated if true, elem freeing will be done when freeing data.
+ * \param edges_mask if not null, true elements give which vert to add to BVH tree.
+ * \param edges_num_active if >= 0, number of active edges to add to BVH tree (else will be computed from mask).
+ */
+BVHTree *bvhtree_from_mesh_edges_ex(
+ BVHTreeFromMesh *data,
+ const MVert *vert, const bool vert_allocated,
+ const MEdge *edge, const int edges_num, const bool edge_allocated,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ BVHTree *tree = bvhtree_from_mesh_edges_create_tree(
+ vert, edge, edges_num, edges_mask, edges_num_active,
+ epsilon, tree_type, axis);
+
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_edges_setup_data(
+ data, tree, false, epsilon, vert, vert_allocated, edge, edge_allocated);
+
+ return tree;
}
/** \} */
@@ -751,7 +795,7 @@ BVHTree *bvhtree_from_mesh_edges(
static BVHTree *bvhtree_from_mesh_faces_create_tree(
float epsilon, int tree_type, int axis,
- MVert *vert, MFace *face, const int faces_num,
+ const MVert *vert, const MFace *face, const int faces_num,
const BLI_bitmap *faces_mask, int faces_num_active)
{
BVHTree *tree = NULL;
@@ -795,34 +839,23 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(
static void bvhtree_from_mesh_faces_setup_data(
BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon,
- MVert *vert, const bool vert_allocated,
- MFace *face, const bool face_allocated)
+ const MVert *vert, const bool vert_allocated,
+ const MFace *face, const bool face_allocated)
{
memset(data, 0, sizeof(*data));
- if (tree) {
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- data->nearest_callback = mesh_faces_nearest_point;
- data->raycast_callback = mesh_faces_spherecast;
- data->nearest_to_ray_callback = NULL;
+ data->nearest_callback = mesh_faces_nearest_point;
+ data->raycast_callback = mesh_faces_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->face = face;
- data->face_allocated = face_allocated;
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->face = face;
+ data->face_allocated = face_allocated;
- data->sphere_radius = epsilon;
- }
- else {
- if (vert_allocated) {
- MEM_freeN(vert);
- }
- if (face_allocated) {
- MEM_freeN(face);
- }
- }
+ data->sphere_radius = epsilon;
}
/* Builds a bvh tree where nodes are the tesselated faces of the given dm */
@@ -865,22 +898,33 @@ BVHTree *bvhtree_from_mesh_faces(
/* printf("BVHTree is already build, using cached tree\n"); */
}
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, vert, vert_allocated, face, face_allocated);
-
- return data->tree;
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_faces_setup_data(
+ data, tree, true, epsilon, vert, vert_allocated, face, face_allocated);
+ }
+ else {
+ if (vert_allocated) {
+ MEM_freeN(vert);
+ }
+ if (face_allocated) {
+ MEM_freeN(face);
+ }
+ memset(data, 0, sizeof(*data));
+ }
+ return tree;
}
/**
* 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 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 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).
+ * \param faces_num_active: if >= 0, number of active faces to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_faces_ex(
- BVHTreeFromMesh *data, MVert *vert, const bool vert_allocated,
- MFace *face, const int numFaces, const bool face_allocated,
+ BVHTreeFromMesh *data, const MVert *vert, const bool vert_allocated,
+ const MFace *face, const int numFaces, const bool face_allocated,
const BLI_bitmap *faces_mask, int faces_num_active,
float epsilon, int tree_type, int axis)
{
@@ -890,9 +934,10 @@ BVHTree *bvhtree_from_mesh_faces_ex(
faces_mask, faces_num_active);
/* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_faces_setup_data(data, tree, false, epsilon, vert, vert_allocated, face, face_allocated);
+ bvhtree_from_mesh_faces_setup_data(
+ data, tree, false, epsilon, vert, vert_allocated, face, face_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -1003,34 +1048,20 @@ static void bvhtree_from_mesh_looptri_setup_data(
{
memset(data, 0, sizeof(*data));
- if (tree) {
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- data->nearest_callback = mesh_looptri_nearest_point;
- data->raycast_callback = mesh_looptri_spherecast;
- data->nearest_to_ray_callback = NULL;
+ data->nearest_callback = mesh_looptri_nearest_point;
+ data->raycast_callback = mesh_looptri_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->loop = mloop;
- data->loop_allocated = loop_allocated;
- data->looptri = looptri;
- data->looptri_allocated = looptri_allocated;
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->loop = mloop;
+ data->loop_allocated = loop_allocated;
+ data->looptri = looptri;
+ data->looptri_allocated = looptri_allocated;
- data->sphere_radius = epsilon;
- }
- else {
- if (vert_allocated) {
- MEM_freeN((void *)vert);
- }
- if (loop_allocated) {
- MEM_freeN((void *)mloop);
- }
- if (looptri_allocated) {
- MEM_freeN((void *)looptri);
- }
- }
+ data->sphere_radius = epsilon;
}
/**
@@ -1075,7 +1106,6 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(
data->tree = tree;
data->nearest_callback = editmesh_looptri_nearest_point;
data->raycast_callback = editmesh_looptri_spherecast;
- data->nearest_to_ray_callback = NULL;
data->sphere_radius = 0.0f;
data->em = em;
data->cached = bvhCache != NULL;
@@ -1107,7 +1137,6 @@ BVHTree *bvhtree_from_mesh_looptri(
const MLoopTri *looptri = NULL;
bool vert_allocated = false;
bool loop_allocated = false;
- bool looptri_allocated = false;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI);
@@ -1120,12 +1149,7 @@ BVHTree *bvhtree_from_mesh_looptri(
mpoly = DM_get_poly_array(dm, &poly_allocated);
mloop = DM_get_loop_array(dm, &loop_allocated);
- looptri = DM_get_looptri_array(
- dm,
- mvert,
- mpoly, dm->getNumPolys(dm),
- mloop, dm->getNumLoops(dm),
- &looptri_allocated);
+ looptri = dm->getLoopTriArray(dm);
if (poly_allocated) {
MEM_freeN(mpoly);
@@ -1157,14 +1181,25 @@ BVHTree *bvhtree_from_mesh_looptri(
/* printf("BVHTree is already build, using cached tree\n"); */
}
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_looptri_setup_data(
- data, tree, true, epsilon,
- mvert, vert_allocated,
- mloop, loop_allocated,
- looptri, looptri_allocated);
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_looptri_setup_data(
+ data, tree, true, epsilon,
+ mvert, vert_allocated,
+ mloop, loop_allocated,
+ looptri, false);
+ }
+ else {
+ if (vert_allocated) {
+ MEM_freeN(mvert);
+ }
+ if (loop_allocated) {
+ MEM_freeN(mloop);
+ }
+ memset(data, 0, sizeof(*data));
+ }
- return data->tree;
+ return tree;
}
BVHTree *bvhtree_from_mesh_looptri_ex(
@@ -1187,7 +1222,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
mloop, loop_allocated,
looptri, looptri_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -1207,29 +1242,27 @@ void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
/* Frees data allocated by a call to bvhtree_from_mesh_*. */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
{
- if (data->tree) {
- if (!data->cached) {
- BLI_bvhtree_free(data->tree);
- }
-
- if (data->vert_allocated) {
- MEM_freeN((void *)data->vert);
- }
- if (data->edge_allocated) {
- MEM_freeN((void *)data->edge);
- }
- if (data->face_allocated) {
- MEM_freeN((void *)data->face);
- }
- if (data->loop_allocated) {
- MEM_freeN((void *)data->loop);
- }
- if (data->looptri_allocated) {
- MEM_freeN((void *)data->looptri);
- }
+ if (data->tree && !data->cached) {
+ BLI_bvhtree_free(data->tree);
+ }
- memset(data, 0, sizeof(*data));
+ if (data->vert_allocated) {
+ MEM_freeN((void *)data->vert);
+ }
+ if (data->edge_allocated) {
+ MEM_freeN((void *)data->edge);
}
+ if (data->face_allocated) {
+ MEM_freeN((void *)data->face);
+ }
+ if (data->loop_allocated) {
+ MEM_freeN((void *)data->loop);
+ }
+ if (data->looptri_allocated) {
+ MEM_freeN((void *)data->looptri);
+ }
+
+ memset(data, 0, sizeof(*data));
}
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index deeb35bd880..1916531b066 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -66,7 +66,7 @@ void BKE_cachefiles_exit(void)
void *BKE_cachefile_add(Main *bmain, const char *name)
{
- CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name);
+ CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name, 0);
BKE_cachefile_init(cache_file);
@@ -82,6 +82,7 @@ void BKE_cachefile_init(CacheFile *cache_file)
cache_file->is_sequence = false;
cache_file->scale = 1.0f;
cache_file->handle_mutex = BLI_mutex_alloc();
+ BLI_listbase_clear(&cache_file->object_paths);
}
/** Free (or release) any data used by this cachefile (does not free the cachefile itself). */
@@ -99,16 +100,26 @@ void BKE_cachefile_free(CacheFile *cache_file)
BLI_freelistN(&cache_file->object_paths);
}
-CacheFile *BKE_cachefile_copy(Main *bmain, CacheFile *cache_file)
+/**
+ * Only copy internal data of CacheFile ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_cachefile_copy_data(
+ Main *UNUSED(bmain), CacheFile *cache_file_dst, const CacheFile *UNUSED(cache_file_src), const int UNUSED(flag))
{
- CacheFile *new_cache_file = BKE_libblock_copy(bmain, &cache_file->id);
- new_cache_file->handle = NULL;
-
- BLI_listbase_clear(&cache_file->object_paths);
-
- BKE_id_copy_ensure_local(bmain, &cache_file->id, &new_cache_file->id);
+ cache_file_dst->handle = NULL;
+ BLI_listbase_clear(&cache_file_dst->object_paths);
+}
- return new_cache_file;
+CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file)
+{
+ CacheFile *cache_file_copy;
+ BKE_id_copy_ex(bmain, &cache_file->id, (ID **)&cache_file_copy, 0, false);
+ return cache_file_copy;
}
void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib_local)
@@ -165,10 +176,12 @@ void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, co
const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
+ BKE_cachefile_clean(scene, cache_file);
#ifdef WITH_ALEMBIC
ABC_free_handle(cache_file->handle);
cache_file->handle = ABC_create_handle(filename, NULL);
#endif
+ break;
}
}
}
@@ -215,10 +228,11 @@ void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file)
if (cache_file == mcmd->cache_file) {
#ifdef WITH_ALEMBIC
- CacheReader_free(mcmd->reader);
+ if (mcmd->reader != NULL) {
+ CacheReader_free(mcmd->reader);
+ }
#endif
mcmd->reader = NULL;
- mcmd->object_path[0] = '\0';
}
}
@@ -231,10 +245,11 @@ void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file)
if (cache_file == data->cache_file) {
#ifdef WITH_ALEMBIC
- CacheReader_free(data->reader);
+ if (data->reader != NULL) {
+ CacheReader_free(data->reader);
+ }
#endif
data->reader = NULL;
- data->object_path[0] = '\0';
}
}
}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 85ce399b770..719125b3317 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -86,22 +86,31 @@ void *BKE_camera_add(Main *bmain, const char *name)
{
Camera *cam;
- cam = BKE_libblock_alloc(bmain, ID_CA, name);
+ cam = BKE_libblock_alloc(bmain, ID_CA, name, 0);
BKE_camera_init(cam);
return cam;
}
-Camera *BKE_camera_copy(Main *bmain, Camera *cam)
+/**
+ * Only copy internal data of Camera ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *UNUSED(cam_dst), const Camera *UNUSED(cam_src), const int UNUSED(flag))
{
- Camera *camn;
-
- camn = BKE_libblock_copy(bmain, &cam->id);
-
- BKE_id_copy_ensure_local(bmain, &cam->id, &camn->id);
+ /* Nothing to do! */
+}
- return camn;
+Camera *BKE_camera_copy(Main *bmain, const Camera *cam)
+{
+ Camera *cam_copy;
+ BKE_id_copy_ex(bmain, &cam->id, (ID **)&cam_copy, 0, false);
+ return cam_copy;
}
void BKE_camera_make_local(Main *bmain, Camera *cam, const bool lib_local)
@@ -252,7 +261,7 @@ void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, cons
}
else if (rv3d->persp == RV3D_ORTHO) {
/* orthographic view */
- int sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y);
+ float sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y);
params->clipend *= 0.5f; // otherwise too extreme low zbuffer quality
params->clipsta = -params->clipend;
@@ -337,6 +346,8 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win
viewplane.ymin *= pixsize;
viewplane.ymax *= pixsize;
+ /* Used for rendering (offset by near-clip with perspective views), passed to RE_SetPixelSize.
+ * For viewport drawing 'RegionView3D.pixsize'. */
params->viewdx = pixsize;
params->viewdy = params->ycor * pixsize;
params->viewplane = viewplane;
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index f2dd2a3fcf6..13949e6777d 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -34,10 +34,12 @@
* \ingroup bke
*/
+#include "atomic_ops.h"
+
#include "BLI_math.h"
#include "BLI_edgehash.h"
#include "BLI_utildefines.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BKE_pbvh.h"
#include "BKE_cdderivedmesh.h"
@@ -660,6 +662,11 @@ static void cdDM_drawMappedFaces(
const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ if (cddm->pbvh) {
+ if (G.debug_value == 14)
+ BKE_pbvh_draw_BB(cddm->pbvh);
+ }
+
/* fist, setup common buffers */
GPU_vertex_setup(dm);
GPU_triangle_setup(dm);
@@ -1518,8 +1525,8 @@ static void cdDM_buffer_copy_mcol(
for (i = 0; i < totpoly; i++, mpoly++) {
for (j = 0; j < mpoly->totloop; j++) {
- copy_v3_v3_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r);
- start += 3;
+ copy_v4_v4_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r);
+ start += 4;
}
}
}
@@ -1919,25 +1926,17 @@ void CDDM_recalc_looptri(DerivedMesh *dm)
const unsigned int totloop = dm->numLoopData;
DM_ensure_looptri_data(dm);
+ BLI_assert(totpoly == 0 || cddm->dm.looptris.array_wip != NULL);
BKE_mesh_recalc_looptri(
cddm->mloop, cddm->mpoly,
cddm->mvert,
totloop, totpoly,
- cddm->dm.looptris.array);
-}
+ cddm->dm.looptris.array_wip);
-static const MLoopTri *cdDM_getLoopTriArray(DerivedMesh *dm)
-{
- if (dm->looptris.array) {
- BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
- }
- else {
- dm->recalcLoopTri(dm);
-
- /* ccdm is an exception here, that recalcLoopTri will fill in the array too */
- }
- return dm->looptris.array;
+ BLI_assert(cddm->dm.looptris.array == NULL);
+ atomic_cas_ptr((void **)&cddm->dm.looptris.array, cddm->dm.looptris.array, cddm->dm.looptris.array_wip);
+ cddm->dm.looptris.array_wip = NULL;
}
static void cdDM_free_internal(CDDerivedMesh *cddm)
@@ -1990,8 +1989,6 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->getEdgeDataArray = DM_get_edge_data_layer;
dm->getTessFaceDataArray = DM_get_tessface_data_layer;
- dm->getLoopTriArray = cdDM_getLoopTriArray;
-
dm->calcNormals = CDDM_calc_normals;
dm->calcLoopNormals = CDDM_calc_loop_normals;
dm->calcLoopNormalsSpaceArray = CDDM_calc_loop_normals_spacearr;
@@ -2398,21 +2395,28 @@ DerivedMesh *CDDM_from_editbmesh(BMEditMesh *em, const bool use_mdisps, const bo
use_tessface, em->tottri, (const BMLoop *(*)[3])em->looptris);
}
-static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces)
+static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
+ const bool need_tessface_data,
+ const bool faces_from_tessfaces)
{
+ const bool copy_tessface_data = (faces_from_tessfaces || need_tessface_data);
CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
DerivedMesh *dm = &cddm->dm;
int numVerts = source->numVertData;
int numEdges = source->numEdgeData;
- int numTessFaces = source->numTessFaceData;
+ int numTessFaces = copy_tessface_data ? source->numTessFaceData : 0;
int numLoops = source->numLoopData;
int numPolys = source->numPolyData;
+ /* NOTE: Don't copy tessellation faces if not requested explicitly. */
+
/* ensure these are created if they are made on demand */
source->getVertDataArray(source, CD_ORIGINDEX);
source->getEdgeDataArray(source, CD_ORIGINDEX);
- source->getTessFaceDataArray(source, CD_ORIGINDEX);
source->getPolyDataArray(source, CD_ORIGINDEX);
+ if (copy_tessface_data) {
+ source->getTessFaceDataArray(source, CD_ORIGINDEX);
+ }
/* this initializes dm, and copies all non mvert/medge/mface layers */
DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces,
@@ -2421,23 +2425,37 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces)
dm->cd_flag = source->cd_flag;
dm->dirty = source->dirty;
+ /* Tessellation data is never copied, so tag it here.
+ * Only tag dirty layers if we really ignored tessellation faces.
+ */
+ if (!copy_tessface_data) {
+ dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ }
+
CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
- CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces);
+ if (copy_tessface_data) {
+ CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces);
+ }
/* now add mvert/medge/mface layers */
cddm->mvert = source->dupVertArray(source);
cddm->medge = source->dupEdgeArray(source);
- cddm->mface = source->dupTessFaceArray(source);
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
- CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numTessFaces);
-
- if (!faces_from_tessfaces)
+
+ if (faces_from_tessfaces || copy_tessface_data) {
+ cddm->mface = source->dupTessFaceArray(source);
+ CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numTessFaces);
+ }
+
+ if (!faces_from_tessfaces) {
DM_DupPolys(source, dm);
- else
+ }
+ else {
CDDM_tessfaces_to_faces(dm);
+ }
cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
@@ -2447,12 +2465,17 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces)
DerivedMesh *CDDM_copy(DerivedMesh *source)
{
- return cddm_copy_ex(source, 0);
+ return cddm_copy_ex(source, false, false);
}
DerivedMesh *CDDM_copy_from_tessface(DerivedMesh *source)
{
- return cddm_copy_ex(source, 1);
+ return cddm_copy_ex(source, false, true);
+}
+
+DerivedMesh *CDDM_copy_with_tessface(DerivedMesh *source)
+{
+ return cddm_copy_ex(source, true, false);
}
/* note, the CD_ORIGINDEX layers are all 0, so if there is a direct
@@ -2966,9 +2989,12 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
STACK_DECLARE(mvert);
STACK_DECLARE(oldv);
- MEdge *med, *medge = MEM_mallocN(sizeof(*medge) * totedge, __func__);
- int *olde = MEM_mallocN(sizeof(*olde) * totedge, __func__);
- int *newe = MEM_mallocN(sizeof(*newe) * totedge, __func__);
+ /* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require
+ * generating new edges, and while in 99% cases we'll still end with less final edges than totedge,
+ * cases can be forged that would end requiring more... */
+ MEdge *med, *medge = MEM_mallocN(sizeof(*medge) * (totedge + totloop), __func__);
+ int *olde = MEM_mallocN(sizeof(*olde) * (totedge + totloop), __func__);
+ int *newe = MEM_mallocN(sizeof(*newe) * (totedge + totloop), __func__);
STACK_DECLARE(medge);
STACK_DECLARE(olde);
@@ -3002,7 +3028,7 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
STACK_INIT(mloop, totloop);
STACK_INIT(mpoly, totpoly);
- /* fill newl with destination vertex indices */
+ /* fill newv with destination vertex indices */
mv = cddm->mvert;
c = 0;
for (i = 0; i < totvert; i++, mv++) {
@@ -3091,83 +3117,80 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
mp = cddm->mpoly;
+ mv = cddm->mvert;
for (i = 0; i < totpoly; i++, mp++) {
MPoly *mp_new;
ml = cddm->mloop + mp->loopstart;
/* check faces with all vertices merged */
- {
- bool all_vertices_merged = true;
+ bool all_vertices_merged = true;
- for (j = 0; j < mp->totloop; j++, ml++) {
- if (vtargetmap[ml->v] == -1) {
- all_vertices_merged = false;
- break;
- }
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ if (vtargetmap[ml->v] == -1) {
+ all_vertices_merged = false;
+ /* This will be used to check for poly using several time the same vert. */
+ mv[ml->v].flag &= ~ME_VERT_TMP_TAG;
}
+ else {
+ /* This will be used to check for poly using several time the same vert. */
+ mv[vtargetmap[ml->v]].flag &= ~ME_VERT_TMP_TAG;
+ }
+ }
- if (UNLIKELY(all_vertices_merged)) {
- if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_MAPPED) {
- /* In this mode, all vertices merged is enough to dump face */
- continue;
+ if (UNLIKELY(all_vertices_merged)) {
+ if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_MAPPED) {
+ /* In this mode, all vertices merged is enough to dump face */
+ continue;
+ }
+ else if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) {
+ /* Additional condition for face dump: target vertices must make up an identical face */
+ /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */
+ /* (2) second step is thorough but more costly poly compare */
+ int i_poly, v_target;
+ bool found = false;
+ PolyKey pkey;
+
+ /* Use poly_gset for fast (although not 100% certain) identification of same poly */
+ /* First, make up a poly_summary structure */
+ ml = cddm->mloop + mp->loopstart;
+ pkey.hash_sum = pkey.hash_xor = 0;
+ pkey.totloops = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */
+ pkey.hash_sum += v_target;
+ pkey.hash_xor ^= v_target;
+ pkey.totloops++;
}
- else if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) {
- /* Additional condition for face dump: target vertices must make up an identical face */
- /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */
- /* (2) second step is thorough but more costly poly compare */
- int i_poly, v_target, v_prev;
- bool found = false;
- PolyKey pkey;
-
- /* Use poly_gset for fast (although not 100% certain) identification of same poly */
- /* First, make up a poly_summary structure */
+ if (BLI_gset_haskey(poly_gset, &pkey)) {
+
+ /* There might be a poly that matches this one.
+ * We could just leave it there and say there is, and do a "continue".
+ * ... but we are checking whether there is an exact poly match.
+ * It's not so costly in terms of CPU since it's very rare, just a lot of complex code.
+ */
+
+ /* Consider current loop again */
ml = cddm->mloop + mp->loopstart;
- pkey.hash_sum = pkey.hash_xor = 0;
- pkey.totloops = 0;
- v_prev = vtargetmap[(ml + mp->totloop -1)->v]; /* since it loops around, the prev of first is the last */
- for (j = 0; j < mp->totloop; j++, ml++) {
- v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */
- if (v_target == v_prev) {
- /* consecutive vertices in loop map to the same target: discard */
- /* but what about last to first ? */
- continue;
+ /* Consider the target of the loop's first vert */
+ v_target = vtargetmap[ml->v];
+ /* Now see if v_target belongs to a poly that shares all vertices with source poly,
+ * in same order, or reverse order */
+
+ for (i_poly = 0; i_poly < cddm->pmap[v_target].count; i_poly++) {
+ MPoly *target_poly = cddm->mpoly + *(cddm->pmap[v_target].indices + i_poly);
+
+ if (cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, +1) ||
+ cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, -1))
+ {
+ found = true;
+ break;
}
- pkey.hash_sum += v_target;
- pkey.hash_xor ^= v_target;
- pkey.totloops++;
- v_prev = v_target;
}
- if (BLI_gset_haskey(poly_gset, &pkey)) {
-
- /* There might be a poly that matches this one.
- * We could just leave it there and say there is, and do a "continue".
- * ... but we are checking whether there is an exact poly match.
- * It's not so costly in terms of CPU since it's very rare, just a lot of complex code.
- */
-
- /* Consider current loop again */
- ml = cddm->mloop + mp->loopstart;
- /* Consider the target of the loop's first vert */
- v_target = vtargetmap[ml->v];
- /* Now see if v_target belongs to a poly that shares all vertices with source poly,
- * in same order, or reverse order */
-
- for (i_poly = 0; i_poly < cddm->pmap[v_target].count; i_poly++) {
- MPoly *target_poly = cddm->mpoly + *(cddm->pmap[v_target].indices + i_poly);
-
- if (cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, +1) ||
- cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, -1))
- {
- found = true;
- break;
- }
- }
- if (found) {
- /* Current poly's vertices are mapped to a poly that is strictly identical */
- /* Current poly is dumped */
- continue;
- }
+ if (found) {
+ /* Current poly's vertices are mapped to a poly that is strictly identical */
+ /* Current poly is dumped */
+ continue;
}
}
}
@@ -3181,32 +3204,121 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
ml = cddm->mloop + mp->loopstart;
c = 0;
+ MLoop *last_valid_ml = NULL;
+ MLoop *first_valid_ml = NULL;
+ bool need_edge_from_last_valid_ml = false;
+ bool need_edge_to_first_valid_ml = false;
+ int created_edges = 0;
for (j = 0; j < mp->totloop; j++, ml++) {
- unsigned int v1, v2;
+ const uint mlv = (vtargetmap[ml->v] != -1) ? vtargetmap[ml->v] : ml->v;
+#ifndef NDEBUG
+ {
+ MLoop *next_ml = cddm->mloop + mp->loopstart + ((j + 1) % mp->totloop);
+ uint next_mlv = (vtargetmap[next_ml->v] != -1) ? vtargetmap[next_ml->v] : next_ml->v;
+ med = cddm->medge + ml->e;
+ uint v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ uint v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ BLI_assert((mlv == v1 && next_mlv == v2) || (mlv == v2 && next_mlv == v1));
+ }
+#endif
+ /* A loop is only valid if its matching edge is, and it's not reusing a vertex already used by this poly. */
+ if (LIKELY((newe[ml->e] != -1) && ((mv[mlv].flag & ME_VERT_TMP_TAG) == 0))) {
+ mv[mlv].flag |= ME_VERT_TMP_TAG;
+
+ if (UNLIKELY(last_valid_ml != NULL && need_edge_from_last_valid_ml)) {
+ /* We need to create a new edge between last valid loop and this one! */
+ void **val_p;
+
+ uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
+ uint v2 = mlv;
+ BLI_assert(v1 != v2);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ last_valid_ml->e = GET_INT_FROM_POINTER(*val_p);
+ }
+ else {
+ const int new_eidx = STACK_SIZE(medge);
+ STACK_PUSH(olde, olde[last_valid_ml->e]);
+ STACK_PUSH(medge, cddm->medge[last_valid_ml->e]);
+ medge[new_eidx].v1 = last_valid_ml->v;
+ medge[new_eidx].v2 = ml->v;
+ /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
+ *val_p = SET_INT_IN_POINTER(new_eidx);
+ created_edges++;
+
+ last_valid_ml->e = new_eidx;
+ }
+ need_edge_from_last_valid_ml = false;
+ }
- med = cddm->medge + ml->e;
- v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
- v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
- if (LIKELY(v1 != v2)) {
#ifdef USE_LOOPS
newl[j + mp->loopstart] = STACK_SIZE(mloop);
#endif
STACK_PUSH(oldl, j + mp->loopstart);
- STACK_PUSH(mloop, *ml);
+ last_valid_ml = STACK_PUSH_RET_PTR(mloop);
+ *last_valid_ml = *ml;
+ if (first_valid_ml == NULL) {
+ first_valid_ml = last_valid_ml;
+ }
c++;
+
+ /* We absolutely HAVE to handle edge index remapping here, otherwise potential newly created edges
+ * in that part of code make remapping later totally unreliable. */
+ BLI_assert(newe[ml->e] != -1);
+ last_valid_ml->e = newe[ml->e];
}
+ else {
+ if (last_valid_ml != NULL) {
+ need_edge_from_last_valid_ml = true;
+ }
+ else {
+ need_edge_to_first_valid_ml = true;
+ }
+ }
+ }
+ if (UNLIKELY(last_valid_ml != NULL && !ELEM(first_valid_ml, NULL, last_valid_ml) &&
+ (need_edge_to_first_valid_ml || need_edge_from_last_valid_ml)))
+ {
+ /* We need to create a new edge between last valid loop and first valid one! */
+ void **val_p;
+
+ uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
+ uint v2 = (vtargetmap[first_valid_ml->v] != -1) ? vtargetmap[first_valid_ml->v] : first_valid_ml->v;
+ BLI_assert(v1 != v2);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ last_valid_ml->e = GET_INT_FROM_POINTER(*val_p);
+ }
+ else {
+ const int new_eidx = STACK_SIZE(medge);
+ STACK_PUSH(olde, olde[last_valid_ml->e]);
+ STACK_PUSH(medge, cddm->medge[last_valid_ml->e]);
+ medge[new_eidx].v1 = last_valid_ml->v;
+ medge[new_eidx].v2 = first_valid_ml->v;
+ /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
+ *val_p = SET_INT_IN_POINTER(new_eidx);
+ created_edges++;
+
+ last_valid_ml->e = new_eidx;
+ }
+ need_edge_to_first_valid_ml = need_edge_from_last_valid_ml = false;
}
if (UNLIKELY(c == 0)) {
+ BLI_assert(created_edges == 0);
continue;
}
else if (UNLIKELY(c < 3)) {
STACK_DISCARD(oldl, c);
STACK_DISCARD(mloop, c);
+ if (created_edges > 0) {
+ for (j = STACK_SIZE(medge) - created_edges; j < STACK_SIZE(medge); j++) {
+ BLI_edgehash_remove(ehash, medge[j].v1, medge[j].v2, NULL);
+ }
+ STACK_DISCARD(olde, created_edges);
+ STACK_DISCARD(medge, created_edges);
+ }
continue;
}
-
mp_new = STACK_PUSH_RET_PTR(mpoly);
*mp_new = *mp;
mp_new->totloop = c;
@@ -3231,10 +3343,10 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
/*update edge indices and copy customdata*/
med = medge;
for (i = 0; i < cddm2->dm.numEdgeData; i++, med++) {
- if (newv[med->v1] != -1)
- med->v1 = newv[med->v1];
- if (newv[med->v2] != -1)
- med->v2 = newv[med->v2];
+ BLI_assert(newv[med->v1] != -1);
+ med->v1 = newv[med->v1];
+ BLI_assert(newv[med->v2] != -1);
+ med->v2 = newv[med->v2];
/* Can happen in case vtargetmap contains some double chains, we do not support that. */
BLI_assert(med->v1 != med->v2);
@@ -3245,11 +3357,10 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
/*update loop indices and copy customdata*/
ml = mloop;
for (i = 0; i < cddm2->dm.numLoopData; i++, ml++) {
- if (newe[ml->e] != -1)
- ml->e = newe[ml->e];
- if (newv[ml->v] != -1)
- ml->v = newv[ml->v];
-
+ /* Edge remapping has already be done in main loop handling part above. */
+ BLI_assert(newv[ml->v] != -1);
+ ml->v = newv[ml->v];
+
CustomData_copy_data(&dm->loopData, &cddm2->dm.loopData, oldl[i], i, 1);
}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 28ef3f6f248..dd93606a67c 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -807,7 +807,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
if ( !dm )
return 0;
- DM_ensure_looptri(dm);
cloth_from_mesh ( clmd, dm );
// create springs
@@ -869,12 +868,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
return 0;
}
- for ( i = 0; i < dm->getNumVerts(dm); i++) {
- if ((!(cloth->verts[i].flags & CLOTH_VERT_FLAG_PINNED)) && (cloth->verts[i].goal > ALMOST_ZERO)) {
- cloth_add_spring (clmd, i, i, 0.0, CLOTH_SPRING_TYPE_GOAL);
- }
- }
-
// init our solver
BPH_cloth_solver_init(ob, clmd);
@@ -944,37 +937,6 @@ BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1)
}
}
-// be careful: implicit solver has to be resettet when using this one!
-// --> only for implicit handling of this spring!
-int cloth_add_spring(ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type)
-{
- Cloth *cloth = clmd->clothObject;
- ClothSpring *spring = NULL;
-
- if (cloth) {
- // TODO: look if this spring is already there
-
- spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
-
- if (!spring)
- return 0;
-
- spring->ij = indexA;
- spring->kl = indexB;
- spring->restlen = restlength;
- spring->type = spring_type;
- spring->flags = 0;
- spring->stiffness = 0;
-
- cloth->numsprings++;
-
- BLI_linklist_prepend ( &cloth->springs, spring );
-
- return 1;
- }
- return 0;
-}
-
static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int mvert_num)
{
if (edgelist) {
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 18ca1407ba0..ee25be36855 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -1014,7 +1014,7 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll
}
BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3],
- float r_nor[3], float *r_lambda, float r_w[4])
+ float r_nor[3], float *r_lambda, float r_w[3])
{
float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3];
float nor_v0p2, nor_p1p2;
@@ -1026,7 +1026,7 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float
nor_v0p2 = dot_v3v3(v0p2, r_nor);
madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
- interp_weights_face_v3(r_w, v0, v1, v2, NULL, p2face);
+ interp_weights_tri_v3(r_w, v0, v1, v2, p2face);
sub_v3_v3v3(p1p2, p2, p1);
sub_v3_v3v3(v0p2, p2, v0);
@@ -1085,7 +1085,7 @@ static CollPair *cloth_point_collpair(
const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co;
float lambda /*, distance1 */, distance2;
float facenor[3], v1p1[3], v1p2[3];
- float w[4];
+ float w[3];
if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w))
return collpair;
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 4f3ffed41bc..310255a15c1 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -130,7 +130,7 @@ void curvemapping_free(CurveMapping *cumap)
}
}
-void curvemapping_copy_data(CurveMapping *target, CurveMapping *cumap)
+void curvemapping_copy_data(CurveMapping *target, const CurveMapping *cumap)
{
int a;
@@ -146,7 +146,7 @@ void curvemapping_copy_data(CurveMapping *target, CurveMapping *cumap)
}
}
-CurveMapping *curvemapping_copy(CurveMapping *cumap)
+CurveMapping *curvemapping_copy(const CurveMapping *cumap)
{
if (cumap) {
CurveMapping *cumapn = MEM_dupallocN(cumap);
@@ -508,7 +508,7 @@ static void calchandle_curvemap(
if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
- if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f)||
+ if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) ||
(ydiff1 >= 0.0f && ydiff2 >= 0.0f))
{
bezt->vec[2][1] = bezt->vec[1][1];
@@ -1380,7 +1380,7 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
/* Keep number of threads in sync with the merge parts below. */
ScopesUpdateData data = {
- .scopes = scopes, . ibuf = ibuf,
+ .scopes = scopes, .ibuf = ibuf,
.cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode,
.bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a,
};
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 9d4de30aa2c..7ad2ed91e87 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -42,7 +42,7 @@
#include "BLI_math.h"
#include "BLI_kdopbvh.h"
#include "BLI_utildefines.h"
-
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
#include "DNA_armature_types.h"
@@ -790,7 +790,7 @@ static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bCo
ct = ctn; \
} \
} (void)0
-
+
/* --------- ChildOf Constraint ------------ */
static void childof_new_data(void *cdata)
@@ -1019,7 +1019,7 @@ static void vectomat(const float vec[3], const float target_up[3], short axis, s
}
/* project the up vector onto the plane specified by n */
- project_v3_v3v3(proj, u, n); /* first u onto n... */
+ project_v3_v3v3_normalized(proj, u, n); /* first u onto n... */
sub_v3_v3v3(proj, u, proj); /* then onto the plane */
/* proj specifies the transformation of the up axis */
@@ -1930,7 +1930,7 @@ static void samevolume_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *
/* calculate normalizing scale factor for non-essential values */
if (obsize[data->flag] != 0)
- fac = sqrtf(volume / obsize[data->flag]) / obsize[data->flag];
+ fac = sqrtf(volume / obsize[data->flag]);
/* apply scaling factor to the channels not being kept */
switch (data->flag) {
@@ -4387,23 +4387,22 @@ static void transformcache_copy(bConstraint *con, bConstraint *srccon)
BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path));
dst->cache_file = src->cache_file;
- if (dst->cache_file) {
- id_us_plus(&dst->cache_file->id);
+#ifdef WITH_ALEMBIC
+ if (dst->reader) {
+ CacheReader_incref(dst->reader);
}
+#endif
}
static void transformcache_free(bConstraint *con)
{
bTransformCacheConstraint *data = con->data;
- if (data->cache_file) {
- id_us_min(&data->cache_file->id);
- }
-
if (data->reader) {
#ifdef WITH_ALEMBIC
CacheReader_free(data->reader);
#endif
+ data->reader = NULL;
}
}
@@ -4738,29 +4737,30 @@ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool i
}
/* duplicate all of the constraints in a constraint stack */
-void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern)
+void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern)
{
bConstraint *con, *srccon;
-
+
BLI_listbase_clear(dst);
BLI_duplicatelist(dst, src);
-
+
for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
+
/* make a new copy of the constraint's data */
con->data = MEM_dupallocN(con->data);
-
+
/* only do specific constraints if required */
if (cti) {
/* perform custom copying operations if needed */
if (cti->copy_data)
cti->copy_data(con, srccon);
-
- /* fix usercounts for all referenced data in referenced data */
- if (cti->id_looper)
+
+ /* Fix usercounts for all referenced data that need it. */
+ if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
cti->id_looper(con, con_fix_copied_refs_cb, NULL);
-
+ }
+
/* for proxies we don't want to make extern */
if (do_extern) {
/* go over used ID-links for this constraint to ensure that they are valid for proxies */
@@ -4771,6 +4771,11 @@ void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern)
}
}
+void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern)
+{
+ BKE_constraints_copy_ex(dst, src, 0, do_extern);
+}
+
/* ......... */
bConstraint *BKE_constraints_find_name(ListBase *list, const char *name)
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 90a514781d7..6c6019748d6 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -89,20 +89,33 @@ void BKE_curve_editfont_free(Curve *cu)
}
}
-void BKE_curve_editNurb_keyIndex_free(EditNurb *editnurb)
+static void curve_editNurb_keyIndex_cv_free_cb(void *val)
{
- if (!editnurb->keyindex) {
+ CVKeyIndex *index = val;
+ MEM_freeN(index->orig_cv);
+ MEM_freeN(val);
+}
+
+void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv)
+{
+ BLI_assert(keyindex != NULL);
+ BLI_ghash_remove(keyindex, cv, NULL, curve_editNurb_keyIndex_cv_free_cb);
+}
+
+void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
+{
+ if (!(*keyindex)) {
return;
}
- BLI_ghash_free(editnurb->keyindex, NULL, MEM_freeN);
- editnurb->keyindex = NULL;
+ BLI_ghash_free(*keyindex, NULL, curve_editNurb_keyIndex_cv_free_cb);
+ *keyindex = NULL;
}
void BKE_curve_editNurb_free(Curve *cu)
{
if (cu->editnurb) {
BKE_nurbList_free(&cu->editnurb->nurbs);
- BKE_curve_editNurb_keyIndex_free(cu->editnurb);
+ BKE_curve_editNurb_keyIndex_free(&cu->editnurb->keyindex);
MEM_freeN(cu->editnurb);
cu->editnurb = NULL;
}
@@ -166,7 +179,7 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
{
Curve *cu;
- cu = BKE_libblock_alloc(bmain, ID_CU, name);
+ cu = BKE_libblock_alloc(bmain, ID_CU, name, 0);
cu->type = type;
BKE_curve_init(cu);
@@ -174,42 +187,39 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
return cu;
}
-Curve *BKE_curve_copy(Main *bmain, Curve *cu)
+/**
+ * Only copy internal data of Curve ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const int flag)
{
- Curve *cun;
- int a;
+ BLI_listbase_clear(&cu_dst->nurb);
+ BKE_nurbList_duplicate(&(cu_dst->nurb), &(cu_src->nurb));
- cun = BKE_libblock_copy(bmain, &cu->id);
-
- BLI_listbase_clear(&cun->nurb);
- BKE_nurbList_duplicate(&(cun->nurb), &(cu->nurb));
-
- cun->mat = MEM_dupallocN(cu->mat);
- for (a = 0; a < cun->totcol; a++) {
- id_us_plus((ID *)cun->mat[a]);
- }
+ cu_dst->mat = MEM_dupallocN(cu_src->mat);
- cun->str = MEM_dupallocN(cu->str);
- cun->strinfo = MEM_dupallocN(cu->strinfo);
- cun->tb = MEM_dupallocN(cu->tb);
- cun->bb = MEM_dupallocN(cu->bb);
+ cu_dst->str = MEM_dupallocN(cu_src->str);
+ cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo);
+ cu_dst->tb = MEM_dupallocN(cu_src->tb);
+ cu_dst->bb = MEM_dupallocN(cu_src->bb);
- if (cu->key) {
- cun->key = BKE_key_copy(bmain, cu->key);
- cun->key->from = (ID *)cun;
+ if (cu_src->key) {
+ BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag, false);
}
- cun->editnurb = NULL;
- cun->editfont = NULL;
-
- id_us_plus((ID *)cun->vfont);
- id_us_plus((ID *)cun->vfontb);
- id_us_plus((ID *)cun->vfonti);
- id_us_plus((ID *)cun->vfontbi);
-
- BKE_id_copy_ensure_local(bmain, &cu->id, &cun->id);
+ cu_dst->editnurb = NULL;
+ cu_dst->editfont = NULL;
+}
- return cun;
+Curve *BKE_curve_copy(Main *bmain, const Curve *cu)
+{
+ Curve *cu_copy;
+ BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, 0, false);
+ return cu_copy;
}
void BKE_curve_make_local(Main *bmain, Curve *cu, const bool lib_local)
@@ -455,7 +465,7 @@ void BKE_nurbList_free(ListBase *lb)
BLI_listbase_clear(lb);
}
-Nurb *BKE_nurb_duplicate(Nurb *nu)
+Nurb *BKE_nurb_duplicate(const Nurb *nu)
{
Nurb *newnu;
int len;
@@ -519,7 +529,7 @@ Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
return newnu;
}
-void BKE_nurbList_duplicate(ListBase *lb1, ListBase *lb2)
+void BKE_nurbList_duplicate(ListBase *lb1, const ListBase *lb2)
{
Nurb *nu, *nun;
@@ -731,6 +741,7 @@ BezTriple *BKE_nurb_bezt_get_prev(Nurb *nu, BezTriple *bezt)
BezTriple *bezt_prev;
BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
+ BLI_assert(nu->pntsv <= 1);
if (bezt == nu->bezt) {
if (nu->flagu & CU_NURB_CYCLIC) {
@@ -752,6 +763,7 @@ BPoint *BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp)
BPoint *bp_prev;
BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
+ BLI_assert(nu->pntsv == 1);
if (bp == nu->bp) {
if (nu->flagu & CU_NURB_CYCLIC) {
@@ -768,7 +780,7 @@ BPoint *BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp)
return bp_prev;
}
-void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), struct BezTriple *bezt, float r_normal[3])
+void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), BezTriple *bezt, float r_normal[3])
{
/* calculate the axis matrix from the spline */
float dir_prev[3], dir_next[3];
@@ -783,7 +795,7 @@ void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), struct BezTriple *bezt,
normalize_v3(r_normal);
}
-void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_plane[3])
+void BKE_nurb_bezt_calc_plane(struct Nurb *nu, BezTriple *bezt, float r_plane[3])
{
float dir_prev[3], dir_next[3];
@@ -820,7 +832,7 @@ void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_p
normalize_v3(r_plane);
}
-void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_normal[3])
+void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, BPoint *bp, float r_normal[3])
{
BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
@@ -843,6 +855,34 @@ void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_nor
normalize_v3(r_normal);
}
+void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3])
+{
+ BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
+ BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
+
+ float dir_prev[3] = {0.0f}, dir_next[3] = {0.0f};
+
+ if (bp_prev) {
+ sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec);
+ normalize_v3(dir_prev);
+ }
+ if (bp_next) {
+ sub_v3_v3v3(dir_next, bp->vec, bp_next->vec);
+ normalize_v3(dir_next);
+ }
+ cross_v3_v3v3(r_plane, dir_prev, dir_next);
+
+ /* matches with bones more closely */
+ {
+ float dir_mid[3], tvec[3];
+ add_v3_v3v3(dir_mid, dir_prev, dir_next);
+ cross_v3_v3v3(tvec, r_plane, dir_mid);
+ copy_v3_v3(r_plane, tvec);
+ }
+
+ normalize_v3(r_plane);
+}
+
/* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */
@@ -3999,7 +4039,7 @@ bool BKE_nurb_check_valid_u(struct Nurb *nu)
return true; /* not a nurb, lets assume its valid */
if (nu->pntsu < nu->orderu) return false;
- if (((nu->flag & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) { /* Bezier U Endpoints */
+ if (((nu->flagu & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) { /* Bezier U Endpoints */
if (nu->orderu == 4) {
if (nu->pntsu < 5)
return false; /* bezier with 4 orderu needs 5 points */
@@ -4020,7 +4060,7 @@ bool BKE_nurb_check_valid_v(struct Nurb *nu)
if (nu->pntsv < nu->orderv)
return false;
- if (((nu->flag & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) { /* Bezier V Endpoints */
+ if (((nu->flagv & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) { /* Bezier V Endpoints */
if (nu->orderv == 4) {
if (nu->pntsv < 5)
return false; /* bezier with 4 orderu needs 5 points */
@@ -4099,6 +4139,7 @@ bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles)
MEM_freeN(nu->bp);
nu->bp = NULL;
nu->pntsu = nr;
+ nu->pntsv = 0;
nu->type = CU_BEZIER;
BKE_nurb_handles_calc(nu);
}
@@ -4402,7 +4443,9 @@ bool BKE_curve_center_bounds(Curve *cu, float cent[3])
}
-void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, const float unit_scale)
+void BKE_curve_transform_ex(
+ Curve *cu, float mat[4][4],
+ const bool do_keys, const bool do_props, const float unit_scale)
{
Nurb *nu;
BPoint *bp;
@@ -4416,7 +4459,9 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons
mul_m4_v3(mat, bezt->vec[0]);
mul_m4_v3(mat, bezt->vec[1]);
mul_m4_v3(mat, bezt->vec[2]);
- bezt->radius *= unit_scale;
+ if (do_props) {
+ bezt->radius *= unit_scale;
+ }
}
BKE_nurb_handles_calc(nu);
}
@@ -4424,7 +4469,9 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons
i = nu->pntsu * nu->pntsv;
for (bp = nu->bp; i--; bp++) {
mul_m4_v3(mat, bp->vec);
- bp->radius *= unit_scale;
+ if (do_props) {
+ bp->radius *= unit_scale;
+ }
}
}
}
@@ -4440,10 +4487,12 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons
}
}
-void BKE_curve_transform(Curve *cu, float mat[4][4], const bool do_keys)
+void BKE_curve_transform(
+ Curve *cu, float mat[4][4],
+ const bool do_keys, const bool do_props)
{
float unit_scale = mat4_to_scale(mat);
- BKE_curve_transform_ex(cu, mat, do_keys, unit_scale);
+ BKE_curve_transform_ex(cu, mat, do_keys, do_props, unit_scale);
}
void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys)
@@ -4632,14 +4681,3 @@ void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
BKE_curve_texspace_calc(curve);
}
}
-
-void BKE_curve_eval_path(EvaluationContext *UNUSED(eval_ctx),
- Curve *curve)
-{
- /* TODO(sergey): This will probably need to be a part of
- * the modifier stack still.
- */
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s on %s\n", __func__, curve->id.name);
- }
-}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 612f1f477e1..68acb60f21a 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -33,20 +33,17 @@
/** \file blender/blenkernel/intern/customdata.c
* \ingroup bke
*/
-
-
-#include <math.h>
-#include <string.h>
-#include <assert.h>
#include "MEM_guardedalloc.h"
+#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_ID.h"
#include "BLI_utildefines.h"
-#include "BLI_string.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_mempool.h"
@@ -61,20 +58,16 @@
#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
-#include "data_transfer_intern.h"
-
#include "bmesh.h"
-#include <math.h>
-#include <string.h>
+/* only for customdata_data_transfer_interp_normal_normals */
+#include "data_transfer_intern.h"
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
/* ensure typemap size is ok */
-BLI_STATIC_ASSERT(sizeof(((CustomData *)NULL)->typemap) /
- sizeof(((CustomData *)NULL)->typemap[0]) == CD_NUMTYPES,
- "size mismatch");
+BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "size mismatch");
/********************* Layer type information **********************/
@@ -804,18 +797,15 @@ static void layerInterp_mloopcol(
const float *sub_weights, int count, void *dest)
{
MLoopCol *mc = dest;
- int i;
- const float *sub_weight;
struct {
float a;
float r;
float g;
float b;
- } col;
- col.a = col.r = col.g = col.b = 0;
+ } col = {0};
- sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
+ const float *sub_weight = sub_weights;
+ for (int i = 0; i < count; ++i) {
float weight = weights ? weights[i] : 1;
const MLoopCol *src = sources[i];
if (sub_weights) {
@@ -832,19 +822,16 @@ static void layerInterp_mloopcol(
col.a += src->a * weight;
}
}
-
+
+
/* Subdivide smooth or fractal can cause problems without clamping
* although weights should also not cause this situation */
- CLAMP(col.a, 0.0f, 255.0f);
- CLAMP(col.r, 0.0f, 255.0f);
- CLAMP(col.g, 0.0f, 255.0f);
- CLAMP(col.b, 0.0f, 255.0f);
- /* delay writing to the destination incase dest is in sources */
- mc->r = (int)col.r;
- mc->g = (int)col.g;
- mc->b = (int)col.b;
- mc->a = (int)col.a;
+ /* also delay writing to the destination incase dest is in sources */
+ mc->r = round_fl_to_uchar_clamp(col.r);
+ mc->g = round_fl_to_uchar_clamp(col.g);
+ mc->b = round_fl_to_uchar_clamp(col.b);
+ mc->a = round_fl_to_uchar_clamp(col.a);
}
static int layerMaxNum_mloopcol(void)
@@ -1067,15 +1054,10 @@ static void layerInterp_mcol(
/* Subdivide smooth or fractal can cause problems without clamping
* although weights should also not cause this situation */
- CLAMP(col[j].a, 0.0f, 255.0f);
- CLAMP(col[j].r, 0.0f, 255.0f);
- CLAMP(col[j].g, 0.0f, 255.0f);
- CLAMP(col[j].b, 0.0f, 255.0f);
-
- mc[j].a = (int)col[j].a;
- mc[j].r = (int)col[j].r;
- mc[j].g = (int)col[j].g;
- mc[j].b = (int)col[j].b;
+ mc[j].a = round_fl_to_uchar_clamp(col[j].a);
+ mc[j].r = round_fl_to_uchar_clamp(col[j].r);
+ mc[j].g = round_fl_to_uchar_clamp(col[j].g);
+ mc[j].b = round_fl_to_uchar_clamp(col[j].b);
}
}
@@ -1962,11 +1944,15 @@ void *CustomData_add_layer_named(CustomData *data, int type, int alloctype,
bool CustomData_free_layer(CustomData *data, int type, int totelem, int index)
{
- const int n = index - CustomData_get_layer_index(data, type);
+ const int index_first = CustomData_get_layer_index(data, type);
+ const int n = index - index_first;
int i;
-
- if (index < 0)
+
+ BLI_assert(index >= index_first);
+ if ((index_first == -1) || (n < 0)) {
return false;
+ }
+ BLI_assert(data->layers[index].type == type);
customData_free_layer__internal(&data->layers[index], totelem);
@@ -2011,8 +1997,10 @@ bool CustomData_free_layer_active(CustomData *data, int type, int totelem)
void CustomData_free_layers(CustomData *data, int type, int totelem)
{
- while (CustomData_has_layer(data, type))
- CustomData_free_layer_active(data, type, totelem);
+ const int index = CustomData_get_layer_index(data, type);
+ while (CustomData_free_layer(data, type, totelem, index)) {
+ /* pass */
+ }
}
bool CustomData_has_layer(const CustomData *data, int type)
@@ -2594,7 +2582,7 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, Custom
if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT))
return false;
-#undef TEST_RET
+#undef LAYER_CMP
/* if no layers are on either CustomData's,
* then there was nothing to do... */
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 839673c192b..3bc09c0173b 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -1205,6 +1205,18 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
+ if ((map_vert_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any edges, "
+ "None of the 'Edge' mappings can be used in this case");
+ continue;
+ }
+ if ((map_vert_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any faces, "
+ "None of the 'Face' mappings can be used in this case");
+ continue;
+ }
if (ELEM(0, num_verts_dst, num_verts_src)) {
BKE_report(reports, RPT_ERROR,
"Source or destination meshes do not have any vertices, cannot transfer vertex data");
@@ -1253,6 +1265,12 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
+ if ((map_edge_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any faces, "
+ "None of the 'Face' mappings can be used in this case");
+ continue;
+ }
if (ELEM(0, num_edges_dst, num_edges_src)) {
BKE_report(reports, RPT_ERROR,
"Source or destination meshes do not have any edges, cannot transfer edge data");
@@ -1312,9 +1330,15 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
+ if ((map_loop_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any edges, "
+ "None of the 'Edge' mappings can be used in this case");
+ continue;
+ }
if (ELEM(0, num_loops_dst, num_loops_src)) {
BKE_report(reports, RPT_ERROR,
- "Source or destination meshes do not have any polygons, cannot transfer loop data");
+ "Source or destination meshes do not have any faces, cannot transfer corner data");
continue;
}
@@ -1370,9 +1394,15 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
+ if ((map_poly_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any edges, "
+ "None of the 'Edge' mappings can be used in this case");
+ continue;
+ }
if (ELEM(0, num_polys_dst, num_polys_src)) {
BKE_report(reports, RPT_ERROR,
- "Source or destination meshes do not have any polygons, cannot transfer poly data");
+ "Source or destination meshes do not have any faces, cannot transfer face data");
continue;
}
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 7052e0a7d25..eec8d2478da 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -45,8 +45,8 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -76,7 +76,7 @@ bDeformGroup *BKE_defgroup_new(Object *ob, const char *name)
return defgroup;
}
-void defgroup_copy_list(ListBase *outbase, ListBase *inbase)
+void defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
{
bDeformGroup *defgroup, *defgroupn;
@@ -88,7 +88,7 @@ void defgroup_copy_list(ListBase *outbase, ListBase *inbase)
}
}
-bDeformGroup *defgroup_duplicate(bDeformGroup *ingroup)
+bDeformGroup *defgroup_duplicate(const bDeformGroup *ingroup)
{
bDeformGroup *outgroup;
@@ -509,7 +509,7 @@ int *defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default)
if (use_default)
map[i] = i;
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_num = defgroup_name_index(ob, name_flip);
@@ -545,7 +545,7 @@ int *defgroup_flip_map_single(Object *ob, int *flip_map_len, const bool use_defa
dg = BLI_findlink(&ob->defbase, defgroup);
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_num = defgroup_name_index(ob, name_flip);
@@ -566,7 +566,7 @@ int defgroup_flip_index(Object *ob, int index, const bool use_default)
if (dg) {
char name_flip[sizeof(dg->name)];
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_index = defgroup_name_index(ob, name_flip);
@@ -606,185 +606,6 @@ void defgroup_unique_name(bDeformGroup *dg, Object *ob)
BLI_uniquename_cb(defgroup_unique_check, &data, DATA_("Group"), '.', dg->name, sizeof(dg->name));
}
-static bool is_char_sep(const char c)
-{
- return ELEM(c, '.', ' ', '-', '_');
-}
-
-/**
- * based on `BLI_split_dirfile()` / `os.path.splitext()`,
- * `"a.b.c"` -> (`"a.b"`, `".c"`).
- */
-void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME], char suf[MAX_VGROUP_NAME])
-{
- size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
- size_t i;
-
- body[0] = suf[0] = '\0';
-
- for (i = len; i > 0; i--) {
- if (is_char_sep(string[i])) {
- BLI_strncpy(body, string, i + 1);
- BLI_strncpy(suf, string + i, (len + 1) - i);
- return;
- }
- }
-
- memcpy(body, string, len + 1);
-}
-
-/**
- * `"a.b.c"` -> (`"a."`, `"b.c"`)
- */
-void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char pre[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME])
-{
- size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
- size_t i;
-
- body[0] = pre[0] = '\0';
-
- for (i = 1; i < len; i++) {
- if (is_char_sep(string[i])) {
- i++;
- BLI_strncpy(pre, string, i + 1);
- BLI_strncpy(body, string + i, (len + 1) - i);
- return;
- }
- }
-
- BLI_strncpy(body, string, len);
-}
-
-/**
- * Finds the best possible flipped name. For renaming; check for unique names afterwards.
- *
- * if strip_number: removes number extensions
- *
- * \note don't use sizeof() for 'name' or 'from_name'.
- */
-void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME],
- const bool strip_number)
-{
- int len;
- char prefix[MAX_VGROUP_NAME] = ""; /* The part before the facing */
- char suffix[MAX_VGROUP_NAME] = ""; /* The part after the facing */
- char replace[MAX_VGROUP_NAME] = ""; /* The replacement string */
- char number[MAX_VGROUP_NAME] = ""; /* The number extension string */
- char *index = NULL;
- bool is_set = false;
-
- /* always copy the name, since this can be called with an uninitialized string */
- BLI_strncpy(name, from_name, MAX_VGROUP_NAME);
-
- len = BLI_strnlen(from_name, MAX_VGROUP_NAME);
- if (len < 3) {
- /* we don't do names like .R or .L */
- return;
- }
-
- /* We first check the case with a .### extension, let's find the last period */
- if (isdigit(name[len - 1])) {
- index = strrchr(name, '.'); // last occurrence
- if (index && isdigit(index[1])) { // doesnt handle case bone.1abc2 correct..., whatever!
- if (strip_number == false) {
- BLI_strncpy(number, index, sizeof(number));
- }
- *index = 0;
- len = BLI_strnlen(name, MAX_VGROUP_NAME);
- }
- }
-
- BLI_strncpy(prefix, name, sizeof(prefix));
-
- /* first case; separator . - _ with extensions r R l L */
- if ((len > 1) && is_char_sep(name[len - 2])) {
- is_set = true;
- switch (name[len - 1]) {
- case 'l':
- prefix[len - 1] = 0;
- strcpy(replace, "r");
- break;
- case 'r':
- prefix[len - 1] = 0;
- strcpy(replace, "l");
- break;
- case 'L':
- prefix[len - 1] = 0;
- strcpy(replace, "R");
- break;
- case 'R':
- prefix[len - 1] = 0;
- strcpy(replace, "L");
- break;
- default:
- is_set = false;
- }
- }
-
- /* case; beginning with r R l L, with separator after it */
- if (!is_set && is_char_sep(name[1])) {
- is_set = true;
- switch (name[0]) {
- case 'l':
- strcpy(replace, "r");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'r':
- strcpy(replace, "l");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'L':
- strcpy(replace, "R");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'R':
- strcpy(replace, "L");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- default:
- is_set = false;
- }
- }
-
- if (!is_set && len > 5) {
- /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
- if (((index = BLI_strcasestr(prefix, "right")) == prefix) ||
- (index == prefix + len - 5))
- {
- is_set = true;
- if (index[0] == 'r') {
- strcpy(replace, "left");
- }
- else {
- strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left");
- }
- *index = 0;
- BLI_strncpy(suffix, index + 5, sizeof(suffix));
- }
- else if (((index = BLI_strcasestr(prefix, "left")) == prefix) ||
- (index == prefix + len - 4))
- {
- is_set = true;
- if (index[0] == 'l') {
- strcpy(replace, "right");
- }
- else {
- strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right");
- }
- *index = 0;
- BLI_strncpy(suffix, index + 4, sizeof(suffix));
- }
- }
-
- (void)is_set; /* quiet warning */
-
- BLI_snprintf(name, MAX_VGROUP_NAME, "%s%s%s%s", prefix, replace, suffix, number);
-}
-
float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
{
MDeformWeight *dw = defvert_find_index(dvert, defgroup);
@@ -800,8 +621,17 @@ float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
*/
float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup)
{
- if (defgroup == -1 || dvert == NULL)
+ /* Invalid defgroup index means the vgroup selected is invalid, does not exist, in that case it is OK to return 1.0
+ * (i.e. maximum weight, as if no vgroup was selected).
+ * But in case of valid defgroup and NULL dvert data pointer, it means that vgroup **is** valid,
+ * and just totally empty, so we shall return '0.0' value then!
+ */
+ if (defgroup == -1) {
return 1.0f;
+ }
+ else if (dvert == NULL) {
+ return 0.0f;
+ }
return defvert_find_weight(dvert + index, defgroup);
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 50f8423bbff..3ddf0f43d30 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -544,10 +544,16 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
if (ct->tar->type == OB_MESH)
node3->customdata_mask |= CD_MASK_MDEFORMVERT;
}
- else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK))
+ else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH,
+ CONSTRAINT_TYPE_CLAMPTO,
+ CONSTRAINT_TYPE_SPLINEIK,
+ CONSTRAINT_TYPE_SHRINKWRAP))
+ {
dag_add_relation(dag, node3, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name);
- else
+ }
+ else {
dag_add_relation(dag, node3, node, DAG_RL_OB_DATA, cti->name);
+ }
}
}
@@ -800,6 +806,10 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
/* Actual code uses get_collider_cache */
dag_add_collision_relations(dag, scene, ob, node, part->collision_group, ob->lay, eModifierType_Collision, NULL, true, "Particle Collision");
}
+ else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd && psys->clmd->coll_parms) {
+ /* Hair uses cloth simulation, i.e. get_collision_objects */
+ dag_add_collision_relations(dag, scene, ob, node, psys->clmd->coll_parms->group, ob->lay | scene->lay, eModifierType_Collision, NULL, true, "Hair Collision");
+ }
dag_add_forcefield_relations(dag, scene, ob, node, part->effector_weights, part->type == PART_HAIR, 0, "Particle Force Field");
@@ -877,8 +887,12 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
if (obt->type == OB_MESH)
node2->customdata_mask |= CD_MASK_MDEFORMVERT;
}
- else
+ else if (cti->type == CONSTRAINT_TYPE_SHRINKWRAP) {
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name);
+ }
+ else {
dag_add_relation(dag, node2, node, DAG_RL_OB_OB, cti->name);
+ }
}
addtoroot = 0;
}
@@ -1428,7 +1442,6 @@ static void scene_sort_groups(Main *bmain, Scene *sce)
/* test; are group objects all in this scene? */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
ob->id.tag &= ~LIB_TAG_DOIT;
- ob->id.newid = NULL; /* newid abuse for GroupObject */
}
for (base = sce->base.first; base; base = base->next)
base->object->id.tag |= LIB_TAG_DOIT;
@@ -1459,6 +1472,11 @@ static void scene_sort_groups(Main *bmain, Scene *sce)
group->gobject = listb;
}
}
+
+ /* newid abused for GroupObject, cleanup. */
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
+ ob->id.newid = NULL;
+ }
}
static void dag_scene_tag_rebuild(Scene *sce)
@@ -2000,6 +2018,7 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho
int lasttime;
if (!DEG_depsgraph_use_legacy()) {
+ DEG_scene_flush_update(bmain, sce);
return;
}
@@ -2555,7 +2574,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
}
static void dag_id_flush_update__isDependentTexture(
- void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
+ void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cb_flag))
{
struct { ID *id; bool is_dependent; } *data = userData;
@@ -3035,7 +3054,7 @@ void DAG_id_type_tag(Main *bmain, short idtype)
DAG_id_type_tag(bmain, ID_SCE);
}
- bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1;
+ atomic_fetch_and_or_uint8((uint8_t *)&bmain->id_tag_update[BKE_idcode_to_index(idtype)], 1);
}
int DAG_id_type_tagged(Main *bmain, short idtype)
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 49db75a0474..2a300cbe47b 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -167,10 +167,12 @@ void BKE_displist_normals_add(ListBase *lb)
if (dl->nors == NULL) {
dl->nors = MEM_callocN(sizeof(float) * 3, "dlnors");
- if (dl->verts[2] < 0.0f)
+ if (dl->flag & DL_BACK_CURVE) {
dl->nors[2] = -1.0f;
- else
+ }
+ else {
dl->nors[2] = 1.0f;
+ }
}
}
else if (dl->type == DL_SURF) {
@@ -469,6 +471,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj
sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__);
while (cont) {
+ int dl_flag_accum = 0;
cont = 0;
totvert = 0;
nextcol = 0;
@@ -514,6 +517,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj
nextcol = 1;
}
}
+ dl_flag_accum |= dl->flag;
}
dl = dl->next;
}
@@ -526,6 +530,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj
if (tot) {
dlnew = MEM_callocN(sizeof(DispList), "filldisplist");
dlnew->type = DL_INDEX3;
+ dlnew->flag = (dl_flag_accum & (DL_BACK_CURVE | DL_FRONT_CURVE));
dlnew->col = colnr;
dlnew->nr = totvert;
dlnew->parts = tot;
@@ -603,6 +608,7 @@ static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase)
dlnew->nr = dl->parts;
dlnew->parts = 1;
dlnew->type = DL_POLY;
+ dlnew->flag = DL_BACK_CURVE;
dlnew->col = dl->col;
dlnew->charidx = dl->charidx;
@@ -623,6 +629,7 @@ static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase)
dlnew->nr = dl->parts;
dlnew->parts = 1;
dlnew->type = DL_POLY;
+ dlnew->flag = DL_FRONT_CURVE;
dlnew->col = dl->col;
dlnew->charidx = dl->charidx;
@@ -819,7 +826,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
if (editmode)
required_mode |= eModifierMode_Editmode;
- if (cu->editnurb == NULL) {
+ if (!editmode) {
keyVerts = BKE_key_evaluate_object(ob, &numVerts);
if (keyVerts) {
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 66070923153..ae896176b6d 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -32,6 +32,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_kdtree.h"
+#include "BLI_string_utils.h"
#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -215,6 +216,7 @@ typedef struct ImgSeqFormatData {
/* adjacency data flags */
#define ADJ_ON_MESH_EDGE (1 << 0)
+#define ADJ_BORDER_PIXEL (1 << 1)
typedef struct PaintAdjData {
int *n_target; /* array of neighboring point indexes, for single sample use (n_index + neigh_num) */
@@ -222,6 +224,8 @@ typedef struct PaintAdjData {
int *n_num; /* num of neighs for each point */
int *flags; /* vertex adjacency flags */
int total_targets; /* size of n_target */
+ int *border; /* indices of border pixels (only for texture paint) */
+ int total_border; /* size of border */
} PaintAdjData;
/***************************** General Utils ******************************/
@@ -822,6 +826,8 @@ static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
MEM_freeN(data->adj_data->n_target);
if (data->adj_data->flags)
MEM_freeN(data->adj_data->flags);
+ if (data->adj_data->border)
+ MEM_freeN(data->adj_data->border);
MEM_freeN(data->adj_data);
data->adj_data = NULL;
}
@@ -1298,6 +1304,8 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b
ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets");
ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags");
ad->total_targets = neigh_points;
+ ad->border = NULL;
+ ad->total_border = 0;
/* in case of allocation error, free memory */
if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
@@ -1889,8 +1897,8 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
/* apply weights into a vertex group, if doesnt exists add a new layer */
if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
- dvert = CustomData_add_layer_named(&result->vertData, CD_MDEFORMVERT, CD_CALLOC,
- NULL, sData->total_points, surface->output_name);
+ dvert = CustomData_add_layer(&result->vertData, CD_MDEFORMVERT, CD_CALLOC,
+ NULL, sData->total_points);
}
if (defgrp_index != -1 && dvert) {
int i;
@@ -2052,9 +2060,6 @@ DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scen
if (pmd->canvas) {
DerivedMesh *ret;
- /* For now generate looptris in every case */
- DM_ensure_looptri(dm);
-
/* Update canvas data for a new frame */
dynamicPaint_frameUpdate(pmd, scene, ob, dm);
@@ -2064,9 +2069,6 @@ DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scen
return ret;
}
else {
- /* For now generate looptris in every case */
- DM_ensure_looptri(dm);
-
/* Update canvas data for a new frame */
dynamicPaint_frameUpdate(pmd, scene, ob, dm);
@@ -2295,6 +2297,36 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
#undef JITTER_SAMPLES
+static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri, const MLoopUV *mloopuv, int tri_index, const float point[2])
+{
+ float min_distance = FLT_MAX;
+
+ for (int i = 0; i < 3; i++) {
+ const float dist_squared = dist_squared_to_line_segment_v2(
+ point,
+ mloopuv[mlooptri[tri_index].tri[(i + 0)]].uv,
+ mloopuv[mlooptri[tri_index].tri[(i + 1) % 3]].uv
+ );
+
+ if (dist_squared < min_distance)
+ min_distance = dist_squared;
+ }
+
+ return min_distance;
+}
+
+typedef struct DynamicPaintFindIslandBorderData {
+ const MeshElemMap *vert_to_looptri_map;
+ int w, h, px, py;
+
+ int best_index;
+ float best_weight;
+} DynamicPaintFindIslandBorderData;
+
+static void dynamic_paint_find_island_border(
+ const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
+ int tri_index, const float pixel[2], int in_edge, int depth);
+
/* Tries to find the neighboring pixel in given (uv space) direction.
* Result is used by effect system to move paint on the surface.
*
@@ -2345,167 +2377,160 @@ static int dynamic_paint_find_neighbour_pixel(
* TODO: Implement something more accurate / optimized?
*/
{
- const MLoop *mloop = data->mloop;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
-
- /* Get closest edge to that subpixel on UV map */
+ DynamicPaintFindIslandBorderData bdata = {
+ .vert_to_looptri_map = vert_to_looptri_map,
+ .w = w, .h = h, .px = px, .py = py,
+ .best_index = NOT_FOUND, .best_weight = 1.0f
+ };
float pixel[2];
- /* distances only used for comparison */
- float dist_squared, t_dist_squared;
-
- int edge1_index, edge2_index;
- int e1_index, e2_index, target_tri;
- float closest_point[2], lambda, dir_vec[2];
- int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index;
-
- const float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
- /*
- * Find closest edge to that pixel
- */
+ /* Do a small recursive search for the best island edge. */
+ dynamic_paint_find_island_border(data, &bdata, cPoint->tri_index, pixel, -1, 5);
- /* Dist to first edge */
- e1_index = cPoint->v1;
- e2_index = cPoint->v2;
- edge1_index = 0;
- edge2_index = 1;
- dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
-
- /* Dist to second edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v2;
- e2_index = cPoint->v3;
- edge1_index = 1;
- edge2_index = 2;
- dist_squared = t_dist_squared;
- }
-
- /* Dist to third edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v3;
- e2_index = cPoint->v1;
- edge1_index = 2;
- edge2_index = 0;
- dist_squared = t_dist_squared;
- }
+ return bdata.best_index;
+ }
+}
- /*
- * Now find another face that is linked to that edge
- */
- target_tri = -1;
+static void dynamic_paint_find_island_border(
+ const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
+ int tri_index, const float pixel[2], int in_edge, int depth)
+{
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+
+ const unsigned int *loop_idx = mlooptri[tri_index].tri;
+
+ /* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
+ for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
+ /* but not the edge we have just recursed through */
+ if (edge_idx == in_edge)
+ continue;
+
+ float uv0[2], uv1[2], uv2[2];
+
+ copy_v2_v2(uv0, mloopuv[loop_idx[(edge_idx + 0)]].uv);
+ copy_v2_v2(uv1, mloopuv[loop_idx[(edge_idx + 1) % 3]].uv);
+ copy_v2_v2(uv2, mloopuv[loop_idx[(edge_idx + 2) % 3]].uv);
+
+ /* Verify the target point is on the opposite side of the edge from the third triangle
+ * vertex, to ensure that we always move closer to the goal point. */
+ const float sidep = line_point_side_v2(uv0, uv1, pixel);
+ const float side2 = line_point_side_v2(uv0, uv1, uv2);
+
+ if (side2 == 0.0f)
+ continue;
+
+ /* Hack: allow all edges of the original triangle */
+ const bool correct_side = (in_edge == -1) || (sidep < 0 && side2 > 0) || (sidep > 0 && side2 < 0);
+
+ /* Allow exactly on edge for the non-recursive case */
+ if (!correct_side && sidep != 0.0f)
+ continue;
+
+ /* Now find another face that is linked to that edge. */
+ const int vert0 = mloop[loop_idx[(edge_idx + 0)]].v;
+ const int vert1 = mloop[loop_idx[(edge_idx + 1) % 3]].v;
/* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
- for (int i = 0; i < vert_to_looptri_map[e1_index].count; i++) {
- const int lt_index = vert_to_looptri_map[e1_index].indices[i];
- const int v0 = mloop[mlooptri[lt_index].tri[0]].v;
- const int v1 = mloop[mlooptri[lt_index].tri[1]].v;
- const int v2 = mloop[mlooptri[lt_index].tri[2]].v;
+ const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0];
- BLI_assert(ELEM(e1_index, v0, v1, v2));
+ bool found_other = false;
+ int target_tri = -1;
+ int target_edge = -1;
- if (ELEM(e2_index, v0, v1, v2)) {
- if (lt_index == cPoint->tri_index)
- continue;
+ float ouv0[2], ouv1[2];
- target_tri = lt_index;
+ for (int i = 0; i < map->count && !found_other; i++) {
+ const int lt_index = map->indices[i];
- /* Get edge UV index */
- target_uv1 = (e1_index == v0) ? 0 : ((e1_index == v1) ? 1 : 2);
- target_uv2 = (e2_index == v0) ? 0 : ((e2_index == v1) ? 1 : 2);
- break;
- }
- }
+ if (lt_index == tri_index)
+ continue;
- /* If none found pixel is on mesh edge */
- if (target_tri == -1)
- return ON_MESH_EDGE;
+ const unsigned int *other_loop_idx = mlooptri[lt_index].tri;
- /*
- * If target face is connected in UV space as well, just use original index
- */
- s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv;
- s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv;
- t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv;
- t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv;
+ /* Check edges for match, looping in the same order as the outer loop. */
+ for (int j = 0; j < 3; j++) {
+ const int overt0 = mloop[other_loop_idx[(j + 0)]].v;
+ const int overt1 = mloop[other_loop_idx[(j + 1) % 3]].v;
- //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]);
+ /* Allow for swapped vertex order */
+ if (overt0 == vert0 && overt1 == vert1) {
+ found_other = true;
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
+ else if (overt0 == vert1 && overt1 == vert0) {
+ found_other = true;
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
- 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])))
- {
- final_index = x + w * y;
+ if (found_other) {
+ target_tri = lt_index;
+ target_edge = j;
+ break;
+ }
+ }
+ }
- /* If not an active pixel, bail out */
- if (tempPoints[final_index].tri_index == -1)
- return NOT_FOUND;
+ if (!found_other) {
+ if (bdata->best_index < 0)
+ bdata->best_index = ON_MESH_EDGE;
- /* If final point is an "edge pixel", use it's "real" neighbor instead */
- if (tempPoints[final_index].neighbour_pixel != -1) {
- final_index = tempPoints[final_index].neighbour_pixel;
+ continue;
+ }
- /* If we ended up to our origin point */
- if (final_index == (px + w * py))
- return NOT_FOUND;
+ /* If this edge is connected in UV space too, recurse */
+ if (equals_v2v2(uv0, ouv0) && equals_v2v2(uv1, ouv1)) {
+ if (depth > 0 && correct_side) {
+ dynamic_paint_find_island_border(data, bdata, target_tri, pixel, target_edge, depth - 1);
}
- return final_index;
+ continue;
}
+ /* Otherwise try to map to the other side of the edge.
+ * First check if there already is a better solution. */
+ const float dist_squared = dist_squared_to_line_segment_v2(pixel, uv0, uv1);
+
+ if (bdata->best_index >= 0 && dist_squared >= bdata->best_weight)
+ continue;
+
/*
* Find a point that is relatively at same edge position
* on this other face UV
*/
- lambda = closest_to_line_v2(
- closest_point, pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
- CLAMP(lambda, 0.0f, 1.0f);
+ float closest_point[2], dir_vec[2], tgt_pixel[2];
- sub_v2_v2v2(
- dir_vec,
- mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
- mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+ float lambda = closest_to_line_v2(closest_point, pixel, uv0, uv1);
+ CLAMP(lambda, 0.0f, 1.0f);
- mul_v2_fl(dir_vec, lambda);
+ sub_v2_v2v2(dir_vec, ouv1, ouv0);
+ madd_v2_v2v2fl(tgt_pixel, ouv0, dir_vec, lambda);
- copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
- add_v2_v2(pixel, dir_vec);
- pixel[0] = (pixel[0] * (float)w);
- pixel[1] = (pixel[1] * (float)h);
+ int w = bdata->w, h = bdata->h, px = bdata->px, py = bdata->py;
- final_pixel[0] = (int)floorf(pixel[0]);
- final_pixel[1] = (int)floorf(pixel[1]);
+ int final_pixel[2] = { (int)floorf(tgt_pixel[0] * w), (int)floorf(tgt_pixel[1] * h) };
/* If current pixel uv is outside of texture */
- if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h)
- return OUT_OF_TEXTURE;
+ if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h) {
+ if (bdata->best_index == NOT_FOUND)
+ bdata->best_index = OUT_OF_TEXTURE;
+
+ continue;
+ }
- final_index = final_pixel[0] + w * final_pixel[1];
+ const PaintUVPoint *tempPoints = data->tempPoints;
+ int final_index = final_pixel[0] + w * final_pixel[1];
/* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
if (final_index == (px + w * py))
- return NOT_FOUND;
- /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri)
- return NOT_FOUND;
+ continue;
/* If final point is an "edge pixel", use it's "real" neighbor instead */
if (tempPoints[final_index].neighbour_pixel != -1) {
@@ -2513,11 +2538,125 @@ static int dynamic_paint_find_neighbour_pixel(
/* If we ended up to our origin point */
if (final_index == (px + w * py))
- return NOT_FOUND;
+ continue;
+ }
+
+ /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
+ if (tempPoints[final_index].tri_index != target_tri) {
+ /* Check if it's close enough to likely touch the intended triangle. Any triangle
+ * becomes thinner than a pixel at its vertices, so robustness requires some margin. */
+ const float final_pt[2] = { ((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h };
+ const float threshold = SQUARE(0.7f) / (w * h);
+
+ if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold)
+ continue;
}
- return final_index;
+ bdata->best_index = final_index;
+ bdata->best_weight = dist_squared;
+ }
+}
+
+static bool dynamicPaint_pointHasNeighbor(PaintAdjData *ed, int index, int neighbor)
+{
+ const int idx = ed->n_index[index];
+
+ for (int i = 0; i < ed->n_num[index]; i++) {
+ if (ed->n_target[idx + i] == neighbor) {
+ return true;
+ }
}
+
+ return false;
+}
+
+/* Makes the adjacency data symmetric, except for border pixels. I.e. if A is neighbor of B, B is neighbor of A. */
+static bool dynamicPaint_symmetrizeAdjData(PaintAdjData *ed, int active_points)
+{
+ int *new_n_index = MEM_callocN(sizeof(int) * active_points, "Surface Adj Index");
+ int *new_n_num = MEM_callocN(sizeof(int) * active_points, "Surface Adj Counts");
+
+ if (new_n_num && new_n_index) {
+ /* Count symmetrized neigbors */
+ int total_targets = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ total_targets += ed->n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
+
+ assert(!(ed->flags[target] & ADJ_BORDER_PIXEL));
+
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ new_n_num[target]++;
+ total_targets++;
+ }
+ }
+ }
+
+ /* Allocate a new target map */
+ int *new_n_target = MEM_callocN(sizeof(int) * total_targets, "Surface Adj Targets");
+
+ if (new_n_target) {
+ /* Copy existing neighbors to the new map */
+ int n_pos = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ new_n_index[index] = n_pos;
+ memcpy(&new_n_target[n_pos], &ed->n_target[ed->n_index[index]], sizeof(int) * ed->n_num[index]);
+
+ /* Reset count to old, but advance position by new, leaving a gap to fill below. */
+ n_pos += new_n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ assert(n_pos == total_targets);
+
+ /* Add symmetrized - this loop behavior must exactly match the count pass above */
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
+
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ const int num = new_n_num[target]++;
+ new_n_target[new_n_index[target] + num] = index;
+ }
+ }
+ }
+
+ /* Swap maps */
+ MEM_freeN(ed->n_target);
+ ed->n_target = new_n_target;
+
+ MEM_freeN(ed->n_index);
+ ed->n_index = new_n_index;
+
+ MEM_freeN(ed->n_num);
+ ed->n_num = new_n_num;
+
+ ed->total_targets = total_targets;
+ return true;
+ }
+ }
+
+ if (new_n_index)
+ MEM_freeN(new_n_index);
+ if (new_n_num)
+ MEM_freeN(new_n_num);
+
+ return false;
}
int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update)
@@ -2668,30 +2807,28 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
&vert_to_looptri_map, &vert_to_looptri_map_mem,
dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm));
+ int total_border = 0;
+
for (int ty = 0; ty < h; ty++) {
for (int tx = 0; tx < w; tx++) {
const int index = tx + w * ty;
if (tempPoints[index].tri_index != -1) {
- int start_pos = n_pos;
ed->n_index[final_index[index]] = n_pos;
ed->n_num[final_index[index]] = 0;
+ if (tempPoints[index].neighbour_pixel != -1) {
+ ed->flags[final_index[index]] |= ADJ_BORDER_PIXEL;
+ total_border++;
+ }
+
for (int i = 0; i < 8; i++) {
/* Try to find a neighboring pixel in defined direction. If not found, -1 is returned */
const int n_target = dynamic_paint_find_neighbour_pixel(
&data, vert_to_looptri_map, w, h, tx, ty, i);
if (n_target >= 0 && n_target != index) {
- bool duplicate = false;
- for (int j = start_pos; j < n_pos; j++) {
- if (ed->n_target[j] == final_index[n_target]) {
- duplicate = true;
- break;
- }
- }
-
- if (!duplicate) {
+ if (!dynamicPaint_pointHasNeighbor(ed, final_index[index], final_index[n_target])) {
ed->n_target[n_pos] = final_index[n_target];
ed->n_num[final_index[index]]++;
n_pos++;
@@ -2707,6 +2844,57 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
MEM_freeN(vert_to_looptri_map);
MEM_freeN(vert_to_looptri_map_mem);
+
+ /* Make neighbors symmetric */
+ if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) {
+ error = true;
+ }
+
+ /* Create a list of border pixels */
+ ed->border = MEM_callocN(sizeof(int) * total_border, "Border Pixel Index");
+
+ if (ed->border) {
+ ed->total_border = total_border;
+
+ for (int i = 0, next = 0; i < active_points; i++) {
+ if (ed->flags[i] & ADJ_BORDER_PIXEL) {
+ ed->border[next++] = i;
+ }
+ }
+ }
+
+#if 0
+ /* -----------------------------------------------------------------
+ * For debug, write a dump of adjacency data to a file.
+ * -----------------------------------------------------------------*/
+ FILE *dump_file = fopen("dynpaint-adj-data.txt", "w");
+ int *tmp = MEM_callocN(sizeof(int) * active_points, "tmp");
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ if (tempPoints[index].tri_index != -1)
+ tmp[final_index[index]] = index;
+ }
+ }
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ const int fidx = final_index[index];
+
+ if (tempPoints[index].tri_index != -1) {
+ int nidx = tempPoints[index].neighbour_pixel;
+ fprintf(dump_file, "%d\t%d,%d\t%u\t%d,%d\t%d\t", fidx, tx, h-1-ty, tempPoints[index].tri_index, nidx<0?-1:(nidx%w), nidx<0?-1:h-1-(nidx/w), ed->flags[fidx]);
+ for (int i = 0; i < ed->n_num[fidx]; i++) {
+ int tgt = tmp[ed->n_target[ed->n_index[fidx]+i]];
+ fprintf(dump_file, "%s%d,%d", i?" ":"", tgt%w, h-1-tgt/w);
+ }
+ fprintf(dump_file, "\n");
+ }
+ }
+ }
+ MEM_freeN(tmp);
+ fclose(dump_file);
+#endif
}
}
@@ -3739,7 +3927,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
/* velocity brush, only do on main sample */
if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
- float weights[4];
+ float weights[3];
float brushPointVelocity[3];
float velocity[3];
@@ -3748,7 +3936,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
/* calculate barycentric weights for hit point */
- interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord);
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, hitCoord);
/* simple check based on brush surface velocity,
* todo: perhaps implement something that handles volume movement as well */
@@ -4529,6 +4717,10 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
for (step = 0; step < steps; step++) {
for (index = 0; index < sData->total_points; index++) {
int i;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ continue;
+
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
float smudge_str = bData->brush_velocity[index * 4 + 3];
@@ -4708,6 +4900,9 @@ static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
const int numOfNeighs = sData->adj_data->n_num[index];
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
@@ -4737,7 +4932,7 @@ static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
CLAMP(w_factor, 0.0f, 1.0f);
/* mix new wetness and color */
- pPoint->wetness = (1.0f - w_factor) * pPoint->wetness + w_factor * pPoint_prev->wetness;
+ pPoint->wetness = pPoint->wetness + w_factor * (pPoint_prev->wetness - pPoint->wetness);
pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3],
pPoint_prev->e_color, pPoint_prev->e_color[3], w_factor);
}
@@ -4750,6 +4945,9 @@ static void dynamic_paint_effect_shrink_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
const int numOfNeighs = sData->adj_data->n_num[index];
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
@@ -4796,6 +4994,10 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
const PaintPoint *prevPoint = data->prevPoint;
@@ -4964,6 +5166,80 @@ static void dynamicPaint_doEffectStep(
}
}
+static void dynamic_paint_border_cb(void *userdata, const int b_index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ const int index = sData->adj_data->border[b_index];
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Average neighboring points. Intermediaries use premultiplied alpha. */
+ float mix_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float mix_e_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float mix_wetness = 0.0f;
+
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ const int target = n_target[n_idx];
+
+ PaintPoint *pPoint2 = &((PaintPoint *)sData->type_data)[target];
+
+ assert(!(sData->adj_data->flags[target] & ADJ_BORDER_PIXEL));
+
+ madd_v3_v3fl(mix_color, pPoint2->color, pPoint2->color[3]);
+ mix_color[3] += pPoint2->color[3];
+
+ madd_v3_v3fl(mix_e_color, pPoint2->e_color, pPoint2->e_color[3]);
+ mix_e_color[3] += pPoint2->e_color[3];
+
+ mix_wetness += pPoint2->wetness;
+ }
+
+ const float divisor = 1.0f / numOfNeighs;
+
+ if (mix_color[3]) {
+ pPoint->color[3] = mix_color[3] * divisor;
+ mul_v3_v3fl(pPoint->color, mix_color, divisor / pPoint->color[3]);
+ }
+ else {
+ pPoint->color[3] = 0.0f;
+ }
+
+ if (mix_e_color[3]) {
+ pPoint->e_color[3] = mix_e_color[3] * divisor;
+ mul_v3_v3fl(pPoint->e_color, mix_e_color, divisor / pPoint->e_color[3]);
+ }
+ else {
+ pPoint->e_color[3] = 0.0f;
+ }
+
+ pPoint->wetness = mix_wetness / numOfNeighs;
+}
+
+static void dynamicPaint_doBorderStep(DynamicPaintSurface *surface)
+{
+ PaintSurfaceData *sData = surface->data;
+
+ if (!sData->adj_data || !sData->adj_data->border)
+ return;
+
+ /* Don't use prevPoint, relying on the condition that neighbors are never border pixels. */
+ DynamicPaintEffectData data = {
+ .surface = surface
+ };
+
+ BLI_task_parallel_range(
+ 0, sData->adj_data->total_border, &data, dynamic_paint_border_cb, sData->adj_data->total_border > 1000);
+}
+
static void dynamic_paint_wave_step_cb(void *userdata, const int index)
{
const DynamicPaintEffectData *data = userdata;
@@ -5636,6 +5912,11 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
if (force)
MEM_freeN(force);
}
+
+ /* paint island border pixels */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ dynamicPaint_doBorderStep(surface);
+ }
}
return ret;
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 05cf5f6d7bd..be8fcaa6863 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -41,6 +41,8 @@
* is likely to be a little slow.
*/
+#include "atomic_ops.h"
+
#include "BLI_math.h"
#include "BLI_jitter.h"
#include "BLI_bitmap.h"
@@ -149,6 +151,8 @@ static void emDM_ensurePolyCenters(EditDerivedBMesh *bmdm)
const float (*vertexCos)[3];
vertexCos = bmdm->vertexCos;
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
BM_face_calc_center_mean_vcos(bm, efa, polyCos[i], vertexCos);
}
@@ -487,8 +491,6 @@ static void emDM_calc_loop_tangents(
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
BMEditMesh *em = bmdm->em;
BMesh *bm = bmdm->em->bm;
- if (CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) == 0)
- return;
int act_uv_n = -1;
int ren_uv_n = -1;
@@ -496,7 +498,7 @@ static void emDM_calc_loop_tangents(
bool calc_ren = false;
char act_uv_name[MAX_NAME];
char ren_uv_name[MAX_NAME];
- char tangent_mask = 0;
+ short tangent_mask = 0;
DM_calc_loop_tangents_step_0(
&bm->ldata, calc_active_tangent, tangent_names, tangent_names_count,
@@ -506,6 +508,8 @@ static void emDM_calc_loop_tangents(
for (int i = 0; i < tangent_names_count; i++)
if (tangent_names[i][0])
DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, tangent_names[i]);
+ if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, "") == -1)
+ CustomData_add_layer_named(&dm->loopData, CD_TANGENT, CD_CALLOC, NULL, dm->numLoopData, "");
if (calc_act && act_uv_name[0])
DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, act_uv_name);
if (calc_ren && ren_uv_name[0])
@@ -572,7 +576,17 @@ static void emDM_calc_loop_tangents(
continue;
/* needed for orco lookups */
htype_index |= BM_VERT;
+ dm->tangent_mask |= DM_TANGENT_MASK_ORCO;
}
+ else {
+ /* Fill the resulting tangent_mask */
+ int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name);
+ int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ dm->tangent_mask |= 1 << (uv_ind - uv_start);
+ }
+
if (mesh2tangent->precomputedFaceNormals) {
/* needed for face normal lookups */
htype_index |= BM_FACE;
@@ -582,12 +596,6 @@ static void emDM_calc_loop_tangents(
mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
mesh2tangent->tangent = dm->loopData.layers[index].data;
- /* Fill the resulting tangent_mask */
- int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name);
- int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
- BLI_assert(uv_ind != -1 && uv_start != -1);
- BLI_assert(uv_ind - uv_start < MAX_MTFACE);
- dm->tangent_mask |= 1 << (uv_ind - uv_start);
BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
}
@@ -602,15 +610,20 @@ static void emDM_calc_loop_tangents(
#undef USE_LOOPTRI_DETECT_QUADS
#endif
}
+
/* Update active layer index */
- int uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name);
- CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
+ int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
+ if (act_uv_index >= 0) {
+ int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[act_uv_index].name);
+ CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
/* Update render layer index */
- uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
- tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name);
- CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
+ int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
+ if (ren_uv_index >= 0) {
+ int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[ren_uv_index].name);
+ CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
}
/** \} */
@@ -621,45 +634,38 @@ static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm))
/* do nothing */
}
-static void emDM_recalcLoopTri(DerivedMesh *UNUSED(dm))
+static void emDM_recalcLoopTri(DerivedMesh *dm)
{
- /* Nothing to do: emDM tessellation is known,
- * allocate and fill in with emDM_getLoopTriArray */
-}
-
-static const MLoopTri *emDM_getLoopTriArray(DerivedMesh *dm)
-{
- if (dm->looptris.array) {
- BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
- }
- else {
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMLoop *(*looptris)[3] = bmdm->em->looptris;
- MLoopTri *mlooptri;
- const int tottri = bmdm->em->tottri;
- int i;
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMLoop *(*looptris)[3] = bmdm->em->looptris;
+ MLoopTri *mlooptri;
+ const int tottri = bmdm->em->tottri;
+ int i;
- DM_ensure_looptri_data(dm);
- mlooptri = dm->looptris.array;
+ DM_ensure_looptri_data(dm);
+ mlooptri = dm->looptris.array_wip;
- BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
- BLI_assert(tottri == dm->looptris.num);
+ BLI_assert(tottri == 0 || mlooptri != NULL);
+ BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
+ BLI_assert(tottri == dm->looptris.num);
- BM_mesh_elem_index_ensure(bmdm->em->bm, BM_FACE | BM_LOOP);
+ BM_mesh_elem_index_ensure(bmdm->em->bm, BM_FACE | BM_LOOP);
- for (i = 0; i < tottri; i++) {
- BMLoop **ltri = looptris[i];
- MLoopTri *lt = &mlooptri[i];
+ for (i = 0; i < tottri; i++) {
+ BMLoop **ltri = looptris[i];
+ MLoopTri *lt = &mlooptri[i];
- ARRAY_SET_ITEMS(
- lt->tri,
- BM_elem_index_get(ltri[0]),
- BM_elem_index_get(ltri[1]),
- BM_elem_index_get(ltri[2]));
- lt->poly = BM_elem_index_get(ltri[0]->f);
- }
+ ARRAY_SET_ITEMS(
+ lt->tri,
+ BM_elem_index_get(ltri[0]),
+ BM_elem_index_get(ltri[1]),
+ BM_elem_index_get(ltri[2]));
+ lt->poly = BM_elem_index_get(ltri[0]->f);
}
- return dm->looptris.array;
+
+ BLI_assert(dm->looptris.array == NULL);
+ atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip);
+ dm->looptris.array_wip = NULL;
}
static void emDM_foreachMappedVert(
@@ -1030,11 +1036,11 @@ static void emDM_drawMappedFaces(
if (poly_prev != GL_ZERO) glEnd();
glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
}
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
}
else {
@@ -1051,23 +1057,23 @@ static void emDM_drawMappedFaces(
if (!drawSmooth) {
glNormal3fv(polyNos[BM_elem_index_get(efa)]);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
}
else {
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
else glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
else glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
else glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
@@ -1132,11 +1138,11 @@ static void emDM_drawMappedFaces(
if (poly_prev != GL_ZERO) glEnd();
glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
}
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
glVertex3fv(ltri[2]->v->co);
}
else {
@@ -1153,23 +1159,23 @@ static void emDM_drawMappedFaces(
if (!drawSmooth) {
glNormal3fv(efa->no);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
glVertex3fv(ltri[2]->v->co);
}
else {
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
else glNormal3fv(ltri[0]->v->no);
glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
else glNormal3fv(ltri[1]->v->no);
glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
else glNormal3fv(ltri[2]->v->no);
glVertex3fv(ltri[2]->v->co);
@@ -1292,32 +1298,32 @@ static void emDM_drawFacesTex_common(
glNormal3fv(polyNos[BM_elem_index_get(efa)]);
glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
}
else {
glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
else glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
else glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
else glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
@@ -1356,32 +1362,32 @@ static void emDM_drawFacesTex_common(
glNormal3fv(efa->no);
glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
glVertex3fv(ltri[0]->v->co);
glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
glVertex3fv(ltri[1]->v->co);
glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
glVertex3fv(ltri[2]->v->co);
}
else {
glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
else glNormal3fv(ltri[0]->v->no);
glVertex3fv(ltri[0]->v->co);
glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
else glNormal3fv(ltri[1]->v->no);
glVertex3fv(ltri[1]->v->co);
glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
+ if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
else glNormal3fv(ltri[2]->v->no);
glVertex3fv(ltri[2]->v->co);
@@ -2053,20 +2059,25 @@ static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type)
/* layers are store per face for editmesh, we convert to a temporary
* data layer array in the derivedmesh when these are requested */
if (type == CD_MTFACE || type == CD_MCOL) {
- const int type_from = (type == CD_MTFACE) ? CD_MTEXPOLY : CD_MLOOPCOL;
- int index;
const char *bmdata;
char *data;
- index = CustomData_get_layer_index(&bm->pdata, type_from);
+ bool has_type_source = false;
- if (index != -1) {
+ if (type == CD_MTFACE) {
+ has_type_source = CustomData_has_layer(&bm->pdata, CD_MTEXPOLY);
+ }
+ else {
+ has_type_source = CustomData_has_layer(&bm->ldata, CD_MLOOPCOL);
+ }
+
+ if (has_type_source) {
/* offset = bm->pdata.layers[index].offset; */ /* UNUSED */
BMLoop *(*looptris)[3] = bmdm->em->looptris;
const int size = CustomData_sizeof(type);
int i, j;
DM_add_tessface_layer(dm, type, CD_CALLOC, NULL);
- index = CustomData_get_layer_index(&dm->faceData, type);
+ const int index = CustomData_get_layer_index(&dm->faceData, type);
dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
data = datalayer = DM_get_tessface_data_layer(dm, type);
@@ -2243,8 +2254,6 @@ DerivedMesh *getEditDerivedBMesh(
bmdm->dm.getNumLoops = emDM_getNumLoops;
bmdm->dm.getNumPolys = emDM_getNumPolys;
- bmdm->dm.getLoopTriArray = emDM_getLoopTriArray;
-
bmdm->dm.getVert = emDM_getVert;
bmdm->dm.getVertCo = emDM_getVertCo;
bmdm->dm.getVertNo = emDM_getVertNo;
@@ -2625,7 +2634,7 @@ static void statvis_calc_distort(
vertexCos[BM_elem_index_get(l_iter->next->v)]);
}
else {
- BM_loop_calc_face_normal(l_iter, no_corner);
+ BM_loop_calc_face_normal_safe(l_iter, no_corner);
}
/* simple way to detect (what is most likely) concave */
if (dot_v3v3(f_no, no_corner) < 0.0f) {
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 7e6897a2858..38f5c00941c 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -770,7 +770,7 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
force[1] = (0.5f - result->tg) * strength;
force[2] = (0.5f - result->tb) * strength;
}
- else {
+ else if (nabla != 0) {
strength/=nabla;
tex_co[0] += nabla;
@@ -810,6 +810,9 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
force[2] = (dgdx - drdy) * strength;
}
}
+ else {
+ zero_v3(force);
+ }
if (eff->pd->flag & PFIELD_TEX_2D) {
float fac = -dot_v3v3(force, efd->nor);
@@ -845,6 +848,14 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
break;
case PFIELD_FORCE:
normalize_v3(force);
+ if (pd->flag & PFIELD_GRAVITATION){ /* Option: Multiply by 1/distance^2 */
+ if (efd->distance < FLT_EPSILON){
+ strength = 0.0f;
+ }
+ else {
+ strength *= powf(efd->distance, -2.0f);
+ }
+ }
mul_v3_fl(force, strength * efd->falloff);
break;
case PFIELD_VORTEX:
@@ -975,19 +986,19 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
*/
void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
{
-/*
- * Modifies the force on a particle according to its
- * relation with the effector object
- * Different kind of effectors include:
- * Forcefields: Gravity-like attractor
- * (force power is related to the inverse of distance to the power of a falloff value)
- * Vortex fields: swirling effectors
- * (particles rotate around Z-axis of the object. otherwise, same relation as)
- * (Forcefields, but this is not done through a force/acceleration)
- * Guide: particles on a path
- * (particles are guided along a curve bezier or old nurbs)
- * (is independent of other effectors)
- */
+ /*
+ * Modifies the force on a particle according to its
+ * relation with the effector object
+ * Different kind of effectors include:
+ * Forcefields: Gravity-like attractor
+ * (force power is related to the inverse of distance to the power of a falloff value)
+ * Vortex fields: swirling effectors
+ * (particles rotate around Z-axis of the object. otherwise, same relation as)
+ * (Forcefields, but this is not done through a force/acceleration)
+ * Guide: particles on a path
+ * (particles are guided along a curve bezier or old nurbs)
+ * (is independent of other effectors)
+ */
EffectorCache *eff;
EffectorData efd;
int p=0, tot = 1, step = 1;
@@ -1127,7 +1138,7 @@ static void debug_data_insert(SimDebugData *debug_data, SimDebugElement *elem)
BLI_ghash_insert(debug_data->gh, elem, elem);
}
-void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], float r, float g, float b, const char *category, unsigned int hash)
+void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], const char *str, float r, float g, float b, const char *category, unsigned int hash)
{
unsigned int category_hash = BLI_ghashutil_strhash_p(category);
SimDebugElement *elem;
@@ -1146,8 +1157,18 @@ void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[
elem->color[0] = r;
elem->color[1] = g;
elem->color[2] = b;
- copy_v3_v3(elem->v1, v1);
- copy_v3_v3(elem->v2, v2);
+ if (v1)
+ copy_v3_v3(elem->v1, v1);
+ else
+ zero_v3(elem->v1);
+ if (v2)
+ copy_v3_v3(elem->v2, v2);
+ else
+ zero_v3(elem->v2);
+ if (str)
+ BLI_strncpy(elem->str, str, sizeof(elem->str));
+ else
+ elem->str[0] = '\0';
debug_data_insert(_sim_debug_data, elem);
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index a89d423e7a6..db6c533ab57 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -47,6 +47,7 @@
#include "BLI_math.h"
#include "BLI_easing.h"
#include "BLI_threads.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -125,7 +126,7 @@ void free_fcurves(ListBase *list)
/* ---------------------- Copy --------------------------- */
/* duplicate an F-Curve */
-FCurve *copy_fcurve(FCurve *fcu)
+FCurve *copy_fcurve(const FCurve *fcu)
{
FCurve *fcu_d;
@@ -1216,6 +1217,7 @@ bool driver_get_variable_property(
return true;
}
+#if 0
/* Helper function to obtain a pointer to a Pose Channel (for evaluating drivers) */
static bPoseChannel *dtar_get_pchan_ptr(ChannelDriver *driver, DriverTarget *dtar)
{
@@ -1238,6 +1240,32 @@ static bPoseChannel *dtar_get_pchan_ptr(ChannelDriver *driver, DriverTarget *dta
return NULL;
}
}
+#endif
+
+static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
+{
+ short valid_targets = 0;
+
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+
+ /* check if this target has valid data */
+ if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
+ /* invalid target, so will not have enough targets */
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ }
+ else {
+ /* target seems to be OK now... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ valid_targets++;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END
+
+ return valid_targets;
+}
/* ......... */
@@ -1251,62 +1279,54 @@ static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
/* evaluate 'rotation difference' driver variable */
static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
{
- DriverTarget *dtar1 = &dvar->targets[0];
- DriverTarget *dtar2 = &dvar->targets[1];
- bPoseChannel *pchan, *pchan2;
- float q1[4], q2[4], quat[4], angle;
-
- /* get pose channels, and check if we've got two */
- pchan = dtar_get_pchan_ptr(driver, dtar1);
- pchan2 = dtar_get_pchan_ptr(driver, dtar2);
-
- if (ELEM(NULL, pchan, pchan2)) {
- /* disable this driver, since it doesn't work correctly... */
- driver->flag |= DRIVER_FLAG_INVALID;
-
- /* check what the error was */
- if ((pchan == NULL) && (pchan2 == NULL)) {
- if (G.debug & G_DEBUG) {
- printf("Driver Evaluation Error: Rotational difference failed - first 2 targets invalid\n");
- }
-
- dtar1->flag |= DTAR_FLAG_INVALID;
- dtar2->flag |= DTAR_FLAG_INVALID;
- }
- else if (pchan == NULL) {
- if (G.debug & G_DEBUG) {
- printf("Driver Evaluation Error: Rotational difference failed - first target not valid PoseChannel\n");
- }
-
- dtar1->flag |= DTAR_FLAG_INVALID;
- dtar2->flag &= ~DTAR_FLAG_INVALID;
- }
- else if (pchan2 == NULL) {
- if (G.debug & G_DEBUG) {
- printf("Driver Evaluation Error: Rotational difference failed - second target not valid PoseChannel\n");
- }
-
- dtar1->flag &= ~DTAR_FLAG_INVALID;
- dtar2->flag |= DTAR_FLAG_INVALID;
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
+ /* make sure we have enough valid targets to use - all or nothing for now... */
+ if (driver_check_valid_targets(driver, dvar) != 2) {
+ if (G.debug & G_DEBUG) {
+ printf("RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)\n",
+ valid_targets, dvar->targets[0].id, dvar->targets[1].id);
}
-
- /* stop here... */
return 0.0f;
}
- else {
- dtar1->flag &= ~DTAR_FLAG_INVALID;
- dtar2->flag &= ~DTAR_FLAG_INVALID;
+
+ float (*mat[2])[4];
+
+ /* NOTE: for now, these are all just worldspace */
+ for (int i = 0; i < 2; i++) {
+ /* get pointer to loc values to store in */
+ DriverTarget *dtar = &dvar->targets[i];
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+
+ /* after the checks above, the targets should be valid here... */
+ BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone */
+ if (pchan) {
+ /* bone */
+ mat[i] = pchan->pose_mat;
+ }
+ else {
+ /* object */
+ mat[i] = ob->obmat;
+ }
}
-
+
+ float q1[4], q2[4], quat[4], angle;
+
/* use the final posed locations */
- mat4_to_quat(q1, pchan->pose_mat);
- mat4_to_quat(q2, pchan2->pose_mat);
-
+ mat4_to_quat(q1, mat[0]);
+ mat4_to_quat(q2, mat[1]);
+
invert_qt_normalized(q1);
mul_qt_qtqt(quat, q1, q2);
angle = 2.0f * (saacos(quat[0]));
angle = ABS(angle);
-
+
return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
}
@@ -1316,32 +1336,8 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
{
float loc1[3] = {0.0f, 0.0f, 0.0f};
float loc2[3] = {0.0f, 0.0f, 0.0f};
- short valid_targets = 0;
-
- /* Perform two passes
- *
- * FIRST PASS - to just check that everything works...
- * NOTE: we use loops here to reduce code duplication, though in practice,
- * there can only be 2 items or else we run into some problems later
- */
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
-
- /* check if this target has valid data */
- if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
- /* invalid target, so will not have enough targets */
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- }
- else {
- /* target seems to be OK now... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- valid_targets++;
- }
- }
- DRIVER_TARGETS_LOOPER_END
-
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
/* make sure we have enough valid targets to use - all or nothing for now... */
if (valid_targets < dvar->num_targets) {
if (G.debug & G_DEBUG) {
@@ -1350,8 +1346,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
}
return 0.0f;
}
-
-
+
/* SECOND PASS: get two location values */
/* NOTE: for now, these are all just worldspace */
DRIVER_TARGETS_USED_LOOPER(dvar)
@@ -1569,7 +1564,7 @@ static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF)
dvar_eval_rotDiff, /* eval callback */
2, /* number of targets used */
- {"Bone 1", "Bone 2"}, /* UI names for targets */
+ {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
END_DVAR_TYPEDEF,
@@ -1810,7 +1805,7 @@ void fcurve_free_driver(FCurve *fcu)
}
/* This makes a copy of the given driver */
-ChannelDriver *fcurve_copy_driver(ChannelDriver *driver)
+ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
{
ChannelDriver *ndriver;
@@ -1950,7 +1945,7 @@ float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const fl
BLI_mutex_unlock(&python_driver_lock);
}
#else /* WITH_PYTHON*/
- (void)evaltime;
+ UNUSED_VARS(anim_rna, evaltime);
#endif /* WITH_PYTHON*/
break;
}
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
index 8247336d915..8e98a9f672d 100644
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ b/source/blender/blenkernel/intern/fluidsim.c
@@ -80,8 +80,6 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob,
dm = mesh_create_derived_index_render(scene, ob, CD_MASK_BAREMESH, modifierIndex);
- DM_ensure_looptri(dm);
-
mvert = dm->getVertArray(dm);
mloop = dm->getLoopArray(dm);
looptri = dm->getLoopTriArray(dm);
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 2c301c04100..f1732ee7a9a 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -116,7 +116,7 @@ static void fcm_generator_free(FModifier *fcm)
MEM_freeN(data->coefficients);
}
-static void fcm_generator_copy(FModifier *fcm, FModifier *src)
+static void fcm_generator_copy(FModifier *fcm, const FModifier *src)
{
FMod_Generator *gen = (FMod_Generator *)fcm->data;
FMod_Generator *ogen = (FMod_Generator *)src->data;
@@ -386,7 +386,7 @@ static void fcm_envelope_free(FModifier *fcm)
MEM_freeN(env->data);
}
-static void fcm_envelope_copy(FModifier *fcm, FModifier *src)
+static void fcm_envelope_copy(FModifier *fcm, const FModifier *src)
{
FMod_Envelope *env = (FMod_Envelope *)fcm->data;
FMod_Envelope *oenv = (FMod_Envelope *)src->data;
@@ -877,7 +877,7 @@ static void fcm_python_new_data(void *mdata)
data->prop->type = IDP_GROUP;
}
-static void fcm_python_copy(FModifier *fcm, FModifier *src)
+static void fcm_python_copy(FModifier *fcm, const FModifier *src)
{
FMod_Python *pymod = (FMod_Python *)fcm->data;
FMod_Python *opymod = (FMod_Python *)src->data;
@@ -1040,7 +1040,7 @@ static void fmods_init_typeinfo(void)
/* This function should be used for getting the appropriate type-info when only
* a F-Curve modifier type is known
*/
-const FModifierTypeInfo *get_fmodifier_typeinfo(int type)
+const FModifierTypeInfo *get_fmodifier_typeinfo(const int type)
{
/* initialize the type-info list? */
if (FMI_INIT) {
@@ -1065,7 +1065,7 @@ const FModifierTypeInfo *get_fmodifier_typeinfo(int type)
/* This function should always be used to get the appropriate type-info, as it
* has checks which prevent segfaults in some weird cases.
*/
-const FModifierTypeInfo *fmodifier_get_typeinfo(FModifier *fcm)
+const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
{
/* only return typeinfo for valid modifiers */
if (fcm)
@@ -1117,7 +1117,7 @@ FModifier *add_fmodifier(ListBase *modifiers, int type)
}
/* Make a copy of the specified F-Modifier */
-FModifier *copy_fmodifier(FModifier *src)
+FModifier *copy_fmodifier(const FModifier *src)
{
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
FModifier *dst;
@@ -1142,7 +1142,7 @@ FModifier *copy_fmodifier(FModifier *src)
}
/* Duplicate all of the F-Modifiers in the Modifier stacks */
-void copy_fmodifiers(ListBase *dst, ListBase *src)
+void copy_fmodifiers(ListBase *dst, const ListBase *src)
{
FModifier *fcm, *srcfcm;
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 580842fe176..d6b28cfaf70 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -106,6 +106,23 @@ void BKE_vfont_free(struct VFont *vf)
}
}
+void BKE_vfont_copy_data(Main *UNUSED(bmain), VFont *vfont_dst, const VFont *UNUSED(vfont_src), const int flag)
+{
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+
+ /* Just to be sure, should not have any value actually after reading time. */
+ vfont_dst->temp_pf = NULL;
+
+ if (vfont_dst->packedfile) {
+ vfont_dst->packedfile = dupPackedFile(vfont_dst->packedfile);
+ }
+
+ if (vfont_dst->data) {
+ vfont_dst->data = BLI_vfontdata_copy(vfont_dst->data, flag_subdata);
+ }
+}
+
static void *builtin_font_data = NULL;
static int builtin_font_size = 0;
@@ -249,7 +266,7 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath)
vfd = BLI_vfontdata_from_freetypefont(pf);
if (vfd) {
- vfont = BKE_libblock_alloc(bmain, ID_VF, filename);
+ vfont = BKE_libblock_alloc(bmain, ID_VF, filename, 0);
vfont->data = vfd;
/* if there's a font name, use it for the ID name */
@@ -695,10 +712,14 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
if (ef->selboxes)
MEM_freeN(ef->selboxes);
- if (BKE_vfont_select_get(ob, &selstart, &selend))
- ef->selboxes = MEM_callocN((selend - selstart + 1) * sizeof(EditFontSelBox), "font selboxes");
- else
+ if (BKE_vfont_select_get(ob, &selstart, &selend)) {
+ ef->selboxes_len = (selend - selstart) + 1;
+ ef->selboxes = MEM_callocN(ef->selboxes_len * sizeof(EditFontSelBox), "font selboxes");
+ }
+ else {
+ ef->selboxes_len = 0;
ef->selboxes = NULL;
+ }
selboxes = ef->selboxes;
}
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index 21fc1674dc5..e45a938a4fc 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -40,10 +40,11 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
// function declarations
static FreestyleLineSet *alloc_lineset(void);
-static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset);
+static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset, const int flag);
static FreestyleModuleConfig *alloc_module(void);
static void copy_module(FreestyleModuleConfig *new_module, FreestyleModuleConfig *module);
@@ -78,7 +79,7 @@ void BKE_freestyle_config_free(FreestyleConfig *config)
BLI_freelistN(&config->modules);
}
-void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config)
+void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag)
{
FreestyleLineSet *lineset, *new_lineset;
FreestyleModuleConfig *module, *new_module;
@@ -92,7 +93,7 @@ void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *con
BLI_listbase_clear(&new_config->linesets);
for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
new_lineset = alloc_lineset();
- copy_lineset(new_lineset, lineset);
+ copy_lineset(new_lineset, lineset, flag);
BLI_addtail(&new_config->linesets, (void *)new_lineset);
}
@@ -104,11 +105,9 @@ void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *con
}
}
-static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset)
+static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset, const int flag)
{
new_lineset->linestyle = lineset->linestyle;
- if (new_lineset->linestyle)
- id_us_plus(&new_lineset->linestyle->id);
new_lineset->flags = lineset->flags;
new_lineset->selection = lineset->selection;
new_lineset->qi = lineset->qi;
@@ -117,10 +116,12 @@ static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *linese
new_lineset->edge_types = lineset->edge_types;
new_lineset->exclude_edge_types = lineset->exclude_edge_types;
new_lineset->group = lineset->group;
- if (new_lineset->group) {
- id_us_plus(&new_lineset->group->id);
- }
strcpy(new_lineset->name, lineset->name);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)new_lineset->linestyle);
+ id_us_plus((ID *)new_lineset->group);
+ }
}
static FreestyleModuleConfig *alloc_module(void)
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 2242113b79b..ee0d0b41898 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -382,7 +383,8 @@ bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool set
sizeof(palette->info));
/* make this one the active one */
- if (setactive) {
+ /* NOTE: Always make this active if there's nothing else yet (T50123) */
+ if ((setactive) || (gpd->palettes.first == gpd->palettes.last)) {
BKE_gpencil_palette_setactive(gpd, palette);
}
@@ -625,7 +627,7 @@ bGPdata *BKE_gpencil_data_addnew(const char name[])
bGPdata *gpd;
/* allocate memory for a new block */
- gpd = BKE_libblock_alloc(G.main, ID_GD, name);
+ gpd = BKE_libblock_alloc(G.main, ID_GD, name, 0);
/* initial settings */
gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND);
@@ -751,47 +753,62 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
return gpl_dst;
}
-/* make a copy of a given gpencil datablock */
-bGPdata *BKE_gpencil_data_duplicate(Main *bmain, bGPdata *gpd_src, bool internal_copy)
+/**
+ * Only copy internal data of GreasePencil ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag))
{
- const bGPDlayer *gpl_src;
- bGPDlayer *gpl_dst;
- bGPdata *gpd_dst;
+ /* copy layers */
+ BLI_listbase_clear(&gpd_dst->layers);
+ for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
+ /* make a copy of source layer and its data */
+ bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); /* TODO here too could add unused flags... */
+ BLI_addtail(&gpd_dst->layers, gpl_dst);
+ }
- /* error checking */
- if (gpd_src == NULL) {
- return NULL;
+ /* copy palettes */
+ BLI_listbase_clear(&gpd_dst->palettes);
+ for (const bGPDpalette *palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) {
+ bGPDpalette *palette_dst = BKE_gpencil_palette_duplicate(palette_src); /* TODO here too could add unused flags... */
+ BLI_addtail(&gpd_dst->palettes, palette_dst);
}
-
- /* make a copy of the base-data */
+}
+
+/* make a copy of a given gpencil datablock */
+bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
+{
+ /* Yuck and super-uber-hyper yuck!!!
+ * Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it,
+ * so for now keep old code for that one. */
if (internal_copy) {
+ const bGPDlayer *gpl_src;
+ bGPDlayer *gpl_dst;
+ bGPdata *gpd_dst;
+
/* make a straight copy for undo buffers used during stroke drawing */
gpd_dst = MEM_dupallocN(gpd_src);
+
+ /* copy layers */
+ BLI_listbase_clear(&gpd_dst->layers);
+ for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
+ /* make a copy of source layer and its data */
+ gpl_dst = BKE_gpencil_layer_duplicate(gpl_src);
+ BLI_addtail(&gpd_dst->layers, gpl_dst);
+ }
+
+ /* return new */
+ return gpd_dst;
}
else {
- /* make a copy when others use this */
- gpd_dst = BKE_libblock_copy(bmain, &gpd_src->id);
- }
-
- /* copy layers */
- BLI_listbase_clear(&gpd_dst->layers);
- for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
- /* make a copy of source layer and its data */
- gpl_dst = BKE_gpencil_layer_duplicate(gpl_src);
- BLI_addtail(&gpd_dst->layers, gpl_dst);
- }
- if (!internal_copy) {
- /* copy palettes */
- bGPDpalette *palette_src, *palette_dst;
- BLI_listbase_clear(&gpd_dst->palettes);
- for (palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) {
- palette_dst = BKE_gpencil_palette_duplicate(palette_src);
- BLI_addtail(&gpd_dst->palettes, palette_dst);
- }
+ bGPdata *gpd_copy;
+ BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_copy, 0, false);
+ return gpd_copy;
}
-
- /* return new */
- return gpd_dst;
}
void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
@@ -1263,7 +1280,11 @@ void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
-
+
+ /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
+ if (ELEM(NULL, gpd, oldname, newname))
+ return;
+
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (gps = gpf->strokes.first; gps; gps = gps->next) {
@@ -1282,7 +1303,11 @@ void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name)
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps, *gpsn;
-
+
+ /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
+ if (ELEM(NULL, gpd, name))
+ return;
+
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (gps = gpf->strokes.first; gps; gps = gpsn) {
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index 9b011dbb003..fd6e9681e64 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -79,7 +79,9 @@ Group *BKE_group_add(Main *bmain, const char *name)
{
Group *group;
- group = BKE_libblock_alloc(bmain, ID_GR, name);
+ group = BKE_libblock_alloc(bmain, ID_GR, name, 0);
+ id_us_min(&group->id);
+ id_us_ensure_real(&group->id);
group->layer = (1 << 20) - 1;
group->preview = NULL;
@@ -87,19 +89,32 @@ Group *BKE_group_add(Main *bmain, const char *name)
return group;
}
-Group *BKE_group_copy(Main *bmain, Group *group)
+/**
+ * Only copy internal data of Group ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *group_src, const int flag)
{
- Group *groupn;
-
- groupn = BKE_libblock_copy(bmain, &group->id);
- BLI_duplicatelist(&groupn->gobject, &group->gobject);
+ BLI_duplicatelist(&group_dst->gobject, &group_src->gobject);
/* Do not copy group's preview (same behavior as for objects). */
- groupn->preview = NULL;
-
- BKE_id_copy_ensure_local(bmain, &group->id, &groupn->id);
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
+ BKE_previewimg_id_copy(&group_dst->id, &group_src->id);
+ }
+ else {
+ group_dst->preview = NULL;
+ }
+}
- return groupn;
+Group *BKE_group_copy(Main *bmain, const Group *group)
+{
+ Group *group_copy;
+ BKE_id_copy_ex(bmain, &group->id, (ID **)&group_copy, 0, false);
+ return group_copy;
}
void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local)
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 7669c4ba112..a98a1b13402 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -204,7 +204,7 @@ void BKE_previewimg_clear(struct PreviewImage *prv)
}
}
-PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
+PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
{
PreviewImage *prv_img = NULL;
int i;
@@ -222,7 +222,7 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
}
/** Duplicate preview image from \a id and clear icon_id, to be used by datablock copy functions. */
-void BKE_previewimg_id_copy(ID *new_id, ID *old_id)
+void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
{
PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id);
@@ -239,7 +239,7 @@ void BKE_previewimg_id_copy(ID *new_id, ID *old_id)
}
}
-PreviewImage **BKE_previewimg_id_get_p(ID *id)
+PreviewImage **BKE_previewimg_id_get_p(const ID *id)
{
switch (GS(id->name)) {
#define ID_PRV_CASE(id_code, id_struct) case id_code: { return &((id_struct *)id)->preview; } ((void)0)
@@ -253,6 +253,8 @@ PreviewImage **BKE_previewimg_id_get_p(ID *id)
ID_PRV_CASE(ID_GR, Group);
ID_PRV_CASE(ID_SCE, Scene);
#undef ID_PRV_CASE
+ default:
+ break;
}
return NULL;
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index b2641b110f8..45b41fa01ed 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -90,7 +90,7 @@ IDProperty *IDP_NewIDPArray(const char *name)
return prop;
}
-IDProperty *IDP_CopyIDPArray(const IDProperty *array)
+IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag)
{
/* don't use MEM_dupallocN because this may be part of an array */
IDProperty *narray, *tmp;
@@ -109,7 +109,7 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array)
* then free it. this makes for more maintainable
* code than simply reimplementing the copy functions
* in this loop.*/
- tmp = IDP_CopyProperty(GETPROP(narray, i));
+ tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag);
memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
MEM_freeN(tmp);
}
@@ -117,31 +117,35 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array)
return narray;
}
-void IDP_FreeIDPArray(IDProperty *prop)
+static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
{
int i;
BLI_assert(prop->type == IDP_IDPARRAY);
for (i = 0; i < prop->len; i++)
- IDP_FreeProperty(GETPROP(prop, i));
+ IDP_FreeProperty_ex(GETPROP(prop, i), do_id_user);
if (prop->data.pointer)
MEM_freeN(prop->data.pointer);
}
-/*shallow copies item*/
+/* shallow copies item */
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
{
IDProperty *old;
BLI_assert(prop->type == IDP_IDPARRAY);
+ if (index >= prop->len || index < 0)
+ return;
+
old = GETPROP(prop, index);
- if (index >= prop->len || index < 0) return;
- if (item != old) IDP_FreeProperty(old);
-
- memcpy(GETPROP(prop, index), item, sizeof(IDProperty));
+ if (item != old) {
+ IDP_FreeProperty(old);
+
+ memcpy(old, item, sizeof(IDProperty));
+ }
}
IDProperty *IDP_GetIndexArray(IDProperty *prop, int index)
@@ -281,9 +285,9 @@ void IDP_FreeArray(IDProperty *prop)
}
-static IDProperty *idp_generic_copy(const IDProperty *prop)
+static IDProperty *idp_generic_copy(const IDProperty *prop, const int UNUSED(flag))
{
- IDProperty *newp = MEM_callocN(sizeof(IDProperty), "IDProperty array dup");
+ IDProperty *newp = MEM_callocN(sizeof(IDProperty), __func__);
BLI_strncpy(newp->name, prop->name, MAX_IDPROP_NAME);
newp->type = prop->type;
@@ -294,9 +298,9 @@ static IDProperty *idp_generic_copy(const IDProperty *prop)
return newp;
}
-static IDProperty *IDP_CopyArray(const IDProperty *prop)
+static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag)
{
- IDProperty *newp = idp_generic_copy(prop);
+ IDProperty *newp = idp_generic_copy(prop, flag);
if (prop->data.pointer) {
newp->data.pointer = MEM_dupallocN(prop->data.pointer);
@@ -306,7 +310,7 @@ static IDProperty *IDP_CopyArray(const IDProperty *prop)
int a;
for (a = 0; a < prop->len; a++)
- array[a] = IDP_CopyProperty(array[a]);
+ array[a] = IDP_CopyProperty_ex(array[a], flag);
}
}
newp->len = prop->len;
@@ -359,12 +363,12 @@ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
return prop;
}
-static IDProperty *IDP_CopyString(const IDProperty *prop)
+static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag)
{
IDProperty *newp;
BLI_assert(prop->type == IDP_STRING);
- newp = idp_generic_copy(prop);
+ newp = idp_generic_copy(prop, flag);
if (prop->data.pointer)
newp->data.pointer = MEM_dupallocN(prop->data.pointer);
@@ -433,22 +437,26 @@ void IDP_FreeString(IDProperty *prop)
/* -------------------------------------------------------------------- */
-/* ID Type (not in use yet) */
+/* ID Type */
-/** \name IDProperty ID API (unused)
+/** \name IDProperty ID API
* \{ */
-void IDP_LinkID(IDProperty *prop, ID *id)
-{
- if (prop->data.pointer)
- id_us_min(((ID *)prop->data.pointer));
- prop->data.pointer = id;
- id_us_plus(id);
-}
-void IDP_UnlinkID(IDProperty *prop)
+static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag)
{
- id_us_min(((ID *)prop->data.pointer));
+ IDProperty *newp;
+
+ BLI_assert(prop->type == IDP_ID);
+ newp = idp_generic_copy(prop, flag);
+
+ newp->data.pointer = prop->data.pointer;
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(IDP_Id(newp));
+ }
+
+ return newp;
}
+
/** \} */
@@ -461,16 +469,16 @@ void IDP_UnlinkID(IDProperty *prop)
/**
* Checks if a property with the same name as prop exists, and if so replaces it.
*/
-static IDProperty *IDP_CopyGroup(const IDProperty *prop)
+static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
{
IDProperty *newp, *link;
BLI_assert(prop->type == IDP_GROUP);
- newp = idp_generic_copy(prop);
+ newp = idp_generic_copy(prop, flag);
newp->len = prop->len;
for (link = prop->data.group.first; link; link = link->next) {
- BLI_addtail(&newp->data.group, IDP_CopyProperty(link));
+ BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag));
}
return newp;
@@ -499,14 +507,9 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
break;
default:
{
- IDProperty *tmp = other;
- IDProperty *copy = IDP_CopyProperty(prop);
-
- BLI_insertlinkafter(&dest->data.group, other, copy);
- BLI_remlink(&dest->data.group, tmp);
-
- IDP_FreeProperty(tmp);
- MEM_freeN(tmp);
+ BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop));
+ IDP_FreeProperty(other);
+ MEM_freeN(other);
break;
}
}
@@ -526,11 +529,9 @@ void IDP_SyncGroupTypes(IDProperty *dst, const IDProperty *src, const bool do_ar
if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) ||
(do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) && (prop_src->len != prop_dst->len)))
{
- IDP_FreeFromGroup(dst, prop_dst);
- prop_dst = IDP_CopyProperty(prop_src);
-
- dst->len++;
- BLI_insertlinkbefore(&dst->data.group, prop_dst_next, prop_dst);
+ BLI_insertlinkreplace(&dst->data.group, prop_dst, IDP_CopyProperty(prop_src));
+ IDP_FreeProperty(prop_dst);
+ MEM_freeN(prop_dst);
}
else if (prop_dst->type == IDP_GROUP) {
IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen);
@@ -555,11 +556,7 @@ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
for (prop = src->data.group.first; prop; prop = prop->next) {
for (loop = dest->data.group.first; loop; loop = loop->next) {
if (STREQ(loop->name, prop->name)) {
- IDProperty *copy = IDP_CopyProperty(prop);
-
- BLI_insertlinkafter(&dest->data.group, loop, copy);
-
- BLI_remlink(&dest->data.group, loop);
+ BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop));
IDP_FreeProperty(loop);
MEM_freeN(loop);
break;
@@ -586,9 +583,7 @@ void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop
BLI_assert(prop_exist == IDP_GetPropertyFromGroup(group, prop->name));
if ((prop_exist = IDP_GetPropertyFromGroup(group, prop->name))) {
- BLI_insertlinkafter(&group->data.group, prop_exist, prop);
-
- BLI_remlink(&group->data.group, prop_exist);
+ BLI_insertlinkreplace(&group->data.group, prop_exist, prop);
IDP_FreeProperty(prop_exist);
MEM_freeN(prop_exist);
}
@@ -719,13 +714,13 @@ IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, con
* This is because all ID Property freeing functions free only direct data (not the ID Property
* struct itself), but for Groups the child properties *are* considered
* direct data. */
-static void IDP_FreeGroup(IDProperty *prop)
+static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
{
IDProperty *loop;
BLI_assert(prop->type == IDP_GROUP);
for (loop = prop->data.group.first; loop; loop = loop->next) {
- IDP_FreeProperty(loop);
+ IDP_FreeProperty_ex(loop, do_id_user);
}
BLI_freelistN(&prop->data.group);
}
@@ -737,14 +732,58 @@ static void IDP_FreeGroup(IDProperty *prop)
/** \name IDProperty Main API
* \{ */
+IDProperty *IDP_CopyProperty_ex(const IDProperty *prop, const int flag)
+{
+ switch (prop->type) {
+ case IDP_GROUP: return IDP_CopyGroup(prop, flag);
+ case IDP_STRING: return IDP_CopyString(prop, flag);
+ case IDP_ID: return IDP_CopyID(prop, flag);
+ case IDP_ARRAY: return IDP_CopyArray(prop, flag);
+ case IDP_IDPARRAY: return IDP_CopyIDPArray(prop, flag);
+ default: return idp_generic_copy(prop, flag);
+ }
+}
+
IDProperty *IDP_CopyProperty(const IDProperty *prop)
{
+ return IDP_CopyProperty_ex(prop, 0);
+}
+
+/* Updates ID pointers after an object has been copied */
+/* TODO Nuke this once its only user has been correctly converted to use generic ID management from BKE_library! */
+void IDP_RelinkProperty(struct IDProperty *prop)
+{
+ if (!prop)
+ return;
+
switch (prop->type) {
- case IDP_GROUP: return IDP_CopyGroup(prop);
- case IDP_STRING: return IDP_CopyString(prop);
- case IDP_ARRAY: return IDP_CopyArray(prop);
- case IDP_IDPARRAY: return IDP_CopyIDPArray(prop);
- default: return idp_generic_copy(prop);
+ case IDP_GROUP:
+ {
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ IDP_RelinkProperty(loop);
+ }
+ break;
+ }
+ case IDP_IDPARRAY:
+ {
+ IDProperty *idp_array = IDP_Array(prop);
+ for (int i = 0; i < prop->len; i++) {
+ IDP_RelinkProperty(&idp_array[i]);
+ }
+ break;
+ }
+ case IDP_ID:
+ {
+ ID *id = IDP_Id(prop);
+ if (id && id->newid) {
+ id_us_min(IDP_Id(prop));
+ prop->data.pointer = id->newid;
+ id_us_plus(IDP_Id(prop));
+ }
+ break;
+ }
+ default:
+ break; /* Nothing to do for other IDProp types. */
}
}
@@ -844,6 +883,8 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is
return false;
return true;
}
+ case IDP_ID:
+ return (IDP_Id(prop1) == IDP_Id(prop2));
default:
/* should never get here */
BLI_assert(0);
@@ -867,17 +908,19 @@ bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
* The union is simple to use; see the top of this header file for its definition.
* An example of using this function:
*
- * IDPropertyTemplate val;
- * IDProperty *group, *idgroup, *color;
- * group = IDP_New(IDP_GROUP, val, "group1"); //groups don't need a template.
+ * \code{.c}
+ * IDPropertyTemplate val;
+ * IDProperty *group, *idgroup, *color;
+ * group = IDP_New(IDP_GROUP, val, "group1"); //groups don't need a template.
*
- * val.array.len = 4
- * val.array.type = IDP_FLOAT;
- * color = IDP_New(IDP_ARRAY, val, "color1");
+ * val.array.len = 4
+ * val.array.type = IDP_FLOAT;
+ * color = IDP_New(IDP_ARRAY, val, "color1");
*
- * idgroup = IDP_GetProperties(some_id, 1);
- * IDP_AddToGroup(idgroup, color);
- * IDP_AddToGroup(idgroup, group);
+ * idgroup = IDP_GetProperties(some_id, 1);
+ * IDP_AddToGroup(idgroup, color);
+ * IDP_AddToGroup(idgroup, group);
+ * \endcode
*
* Note that you MUST either attach the id property to an id property group with
* IDP_AddToGroup or MEM_freeN the property, doing anything else might result in
@@ -897,7 +940,7 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
*(float *)&prop->data.val = val->f;
break;
case IDP_DOUBLE:
- prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty double");
*(double *)&prop->data.val = val->d;
break;
case IDP_ARRAY:
@@ -917,6 +960,7 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
prop->len = prop->totallen = val->array.len;
break;
}
+ printf("%s: bad array type.\n", __func__);
return NULL;
}
case IDP_STRING:
@@ -963,6 +1007,14 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
/* heh I think all needed values are set properly by calloc anyway :) */
break;
}
+ case IDP_ID:
+ {
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty datablock");
+ prop->data.pointer = (void *)val->id;
+ prop->type = IDP_ID;
+ id_us_plus(IDP_Id(prop));
+ break;
+ }
default:
{
prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
@@ -977,11 +1029,10 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
}
/**
- * \note this will free all child properties of list arrays and groups!
- * Also, note that this does NOT unlink anything! Plus it doesn't free
- * the actual struct IDProperty struct either.
+ * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs!
+ * But it does not free the actual IDProperty struct itself.
*/
-void IDP_FreeProperty(IDProperty *prop)
+void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
{
switch (prop->type) {
case IDP_ARRAY:
@@ -991,14 +1042,24 @@ void IDP_FreeProperty(IDProperty *prop)
IDP_FreeString(prop);
break;
case IDP_GROUP:
- IDP_FreeGroup(prop);
+ IDP_FreeGroup(prop, do_id_user);
break;
case IDP_IDPARRAY:
- IDP_FreeIDPArray(prop);
+ IDP_FreeIDPArray(prop, do_id_user);
+ break;
+ case IDP_ID:
+ if (do_id_user) {
+ id_us_min(IDP_Id(prop));
+ }
break;
}
}
+void IDP_FreeProperty(IDProperty *prop)
+{
+ IDP_FreeProperty_ex(prop, true);
+}
+
void IDP_ClearProperty(IDProperty *prop)
{
IDP_FreeProperty(prop);
@@ -1006,18 +1067,4 @@ void IDP_ClearProperty(IDProperty *prop)
prop->len = prop->totallen = 0;
}
-/**
- * Unlinks any struct IDProperty<->ID linkage that might be going on.
- *
- * \note currently unused
- */
-void IDP_UnlinkProperty(IDProperty *prop)
-{
- switch (prop->type) {
- case IDP_ID:
- IDP_UnlinkID(prop);
- break;
- }
-}
-
/** \} */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index c9bad2160ff..54f0923cabc 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -62,6 +62,7 @@
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
+#include "BLI_mempool.h"
#include "BLI_threads.h"
#include "BLI_timecode.h" /* for stamp timecode format */
#include "BLI_utildefines.h"
@@ -302,8 +303,11 @@ static void image_free_anims(Image *ima)
* Simply free the image data from memory,
* on display the image can load again (except for render buffers).
*/
-void BKE_image_free_buffers(Image *ima)
+void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
{
+ if (do_lock) {
+ BLI_spin_lock(&image_spin);
+ }
image_free_cached_frames(ima);
image_free_anims(ima);
@@ -322,6 +326,15 @@ void BKE_image_free_buffers(Image *ima)
}
ima->ok = IMA_OK;
+
+ if (do_lock) {
+ BLI_spin_unlock(&image_spin);
+ }
+}
+
+void BKE_image_free_buffers(Image *ima)
+{
+ BKE_image_free_buffers_ex(ima, false);
}
/** Free (or release) any data used by this image (does not free the image itself). */
@@ -381,7 +394,7 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ
{
Image *ima;
- ima = BKE_libblock_alloc(bmain, ID_IM, name);
+ ima = BKE_libblock_alloc(bmain, ID_IM, name, 0);
if (ima) {
image_init(ima, source, type);
}
@@ -432,40 +445,53 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
}
}
-/* empty image block, of similar type and filename */
-Image *BKE_image_copy(Main *bmain, Image *ima)
+/**
+ * Only copy internal data of Image ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_src, const int flag)
{
- Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type);
- ima->id.newid = &nima->id;
-
- BLI_strncpy(nima->name, ima->name, sizeof(ima->name));
+ BKE_color_managed_colorspace_settings_copy(&ima_dst->colorspace_settings, &ima_src->colorspace_settings);
- nima->flag = ima->flag;
- nima->tpageflag = ima->tpageflag;
+ copy_image_packedfiles(&ima_dst->packedfiles, &ima_src->packedfiles);
- nima->gen_x = ima->gen_x;
- nima->gen_y = ima->gen_y;
- nima->gen_type = ima->gen_type;
- copy_v4_v4(nima->gen_color, ima->gen_color);
+ ima_dst->stereo3d_format = MEM_dupallocN(ima_src->stereo3d_format);
+ BLI_duplicatelist(&ima_dst->views, &ima_src->views);
- nima->animspeed = ima->animspeed;
-
- nima->aspx = ima->aspx;
- nima->aspy = ima->aspy;
-
- BKE_color_managed_colorspace_settings_copy(&nima->colorspace_settings, &ima->colorspace_settings);
-
- copy_image_packedfiles(&nima->packedfiles, &ima->packedfiles);
+ /* Cleanup stuff that cannot be copied. */
+ ima_dst->cache = NULL;
+ ima_dst->rr = NULL;
+ for (int i = 0; i < IMA_MAX_RENDER_SLOT; i++) {
+ ima_dst->renders[i] = NULL;
+ }
- /* nima->stere3d_format is already allocated by image_alloc... */
- *nima->stereo3d_format = *ima->stereo3d_format;
- BLI_duplicatelist(&nima->views, &ima->views);
+ BLI_listbase_clear(&ima_dst->anims);
- BKE_previewimg_id_copy(&nima->id, &ima->id);
+ ima_dst->totbind = 0;
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ ima_dst->bindcode[i] = 0;
+ ima_dst->gputexture[i] = NULL;
+ }
+ ima_dst->repbind = NULL;
- BKE_id_copy_ensure_local(bmain, &ima->id, &nima->id);
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&ima_dst->id, &ima_src->id);
+ }
+ else {
+ ima_dst->preview = NULL;
+ }
+}
- return nima;
+/* empty image block, of similar type and filename */
+Image *BKE_image_copy(Main *bmain, const Image *ima)
+{
+ Image *ima_copy;
+ BKE_id_copy_ex(bmain, &ima->id, (ID **)&ima_copy, 0, false);
+ return ima_copy;
}
void BKE_image_make_local(Main *bmain, Image *ima, const bool lib_local)
@@ -1177,7 +1203,6 @@ bool BKE_imtype_is_movie(const char imtype)
switch (imtype) {
case R_IMF_IMTYPE_AVIRAW:
case R_IMF_IMTYPE_AVIJPEG:
- case R_IMF_IMTYPE_QUICKTIME:
case R_IMF_IMTYPE_FFMPEG:
case R_IMF_IMTYPE_H264:
case R_IMF_IMTYPE_THEORA:
@@ -1239,7 +1264,7 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file)
switch (imtype) {
case R_IMF_IMTYPE_BMP:
if (write_file) break;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case R_IMF_IMTYPE_TARGA:
case R_IMF_IMTYPE_RAWTGA:
case R_IMF_IMTYPE_IRIS:
@@ -1249,7 +1274,6 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file)
case R_IMF_IMTYPE_MULTILAYER:
case R_IMF_IMTYPE_DDS:
case R_IMF_IMTYPE_JP2:
- case R_IMF_IMTYPE_QUICKTIME:
case R_IMF_IMTYPE_DPX:
chan_flag |= IMA_CHAN_FLAG_ALPHA;
break;
@@ -1312,7 +1336,6 @@ char BKE_imtype_from_arg(const char *imtype_arg)
else if (STREQ(imtype_arg, "AVIRAW")) return R_IMF_IMTYPE_AVIRAW;
else if (STREQ(imtype_arg, "AVIJPEG")) return R_IMF_IMTYPE_AVIJPEG;
else if (STREQ(imtype_arg, "PNG")) return R_IMF_IMTYPE_PNG;
- else if (STREQ(imtype_arg, "QUICKTIME")) return R_IMF_IMTYPE_QUICKTIME;
else if (STREQ(imtype_arg, "BMP")) return R_IMF_IMTYPE_BMP;
#ifdef WITH_HDR
else if (STREQ(imtype_arg, "HDR")) return R_IMF_IMTYPE_RADHDR;
@@ -1423,7 +1446,7 @@ static bool do_add_image_extension(char *string, const char imtype, const ImageF
}
}
#endif
- else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90, R_IMF_IMTYPE_QUICKTIME etc
+ else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90 etc
if (!(BLI_testextensie_n(string, extension_test = ".jpg", ".jpeg", NULL)))
extension = extension_test;
}
@@ -1431,9 +1454,7 @@ static bool do_add_image_extension(char *string, const char imtype, const ImageF
if (extension) {
/* prefer this in many cases to avoid .png.tga, but in certain cases it breaks */
/* remove any other known image extension */
- if (BLI_testextensie_array(string, imb_ext_image) ||
- (G.have_quicktime && BLI_testextensie_array(string, imb_ext_image_qt)))
- {
+ if (BLI_testextensie_array(string, imb_ext_image)) {
return BLI_replace_extension(string, FILE_MAX, extension);
}
else {
@@ -1709,7 +1730,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
}
{
- Render *re = RE_GetRender(scene->id.name);
+ Render *re = RE_GetSceneRender(scene);
RenderStats *stats = re ? RE_GetStats(re) : NULL;
if (stats && (scene->r.stamp & R_STAMP_RENDERTIME)) {
@@ -2217,8 +2238,10 @@ void BKE_imbuf_write_prepare(ImBuf *ibuf, const ImageFormatData *imf)
ibuf->foptions.flag |= OPENEXR_HALF;
ibuf->foptions.flag |= (imf->exr_codec & OPENEXR_COMPRESS);
- if (!(imf->flag & R_IMF_FLAG_ZBUF))
- ibuf->zbuf_float = NULL; /* signal for exr saving */
+ if (!(imf->flag & R_IMF_FLAG_ZBUF)) {
+ /* Signal for exr saving. */
+ IMB_freezbuffloatImBuf(ibuf);
+ }
}
#endif
@@ -2738,7 +2761,6 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
}
}
-#define PASSTYPE_UNSET -1
/* return renderpass for a given pass index and active view */
/* fallback to available if there are missing passes for active view */
static RenderPass *image_render_pass_get(RenderLayer *rl, const int pass, const int view, int *r_passindex)
@@ -2747,7 +2769,7 @@ static RenderPass *image_render_pass_get(RenderLayer *rl, const int pass, const
RenderPass *rpass;
int rp_index = 0;
- int rp_passtype = PASSTYPE_UNSET;
+ const char *rp_name = "";
for (rpass = rl->passes.first; rpass; rpass = rpass->next, rp_index++) {
if (rp_index == pass) {
@@ -2757,12 +2779,12 @@ static RenderPass *image_render_pass_get(RenderLayer *rl, const int pass, const
break;
}
else {
- rp_passtype = rpass->passtype;
+ rp_name = rpass->name;
}
}
/* multiview */
- else if ((rp_passtype != PASSTYPE_UNSET) &&
- (rpass->passtype == rp_passtype) &&
+ else if (rp_name[0] &&
+ STREQ(rpass->name, rp_name) &&
(rpass->view_id == view))
{
rpass_ret = rpass;
@@ -2782,7 +2804,6 @@ static RenderPass *image_render_pass_get(RenderLayer *rl, const int pass, const
return rpass_ret;
}
-#undef PASSTYPE_UNSET
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesnt use the index! */
@@ -2863,7 +2884,7 @@ bool BKE_image_is_stereo(Image *ima)
{
return BKE_image_is_multiview(ima) &&
(BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) &&
- BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)));
+ BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)));
}
static void image_init_multilayer_multiview(Image *ima, RenderResult *rr)
@@ -2903,7 +2924,7 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
}
else if (ima->type == IMA_TYPE_R_RESULT) {
if (ima->render_slot == ima->last_render_slot)
- rr = RE_AcquireResultRead(RE_GetRender(scene->id.name));
+ rr = RE_AcquireResultRead(RE_GetSceneRender(scene));
else
rr = ima->renders[ima->render_slot];
@@ -2921,7 +2942,7 @@ void BKE_image_release_renderresult(Scene *scene, Image *ima)
}
else if (ima->type == IMA_TYPE_R_RESULT) {
if (ima->render_slot == ima->last_render_slot)
- RE_ReleaseResult(RE_GetRender(scene->id.name));
+ RE_ReleaseResult(RE_GetSceneRender(scene));
}
}
@@ -2941,7 +2962,7 @@ void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot)
{
/* called right before rendering, ima->renders contains render
* result pointers for everything but the current render */
- Render *re = RE_GetRender(scene->id.name);
+ Render *re = RE_GetSceneRender(scene);
int slot = ima->render_slot, last = ima->last_render_slot;
if (slot != last) {
@@ -3160,7 +3181,7 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons
struct ImBuf *ibuf;
char name[FILE_MAX];
int flag;
- ImageUser iuser_t;
+ ImageUser iuser_t = {0};
/* XXX temp stuff? */
if (ima->lastframe != frame)
@@ -3168,8 +3189,12 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons
ima->lastframe = frame;
- if (iuser)
+ if (iuser) {
iuser_t = *iuser;
+ }
+ else {
+ /* TODO(sergey): Do we need to initialize something here? */
+ }
iuser_t.view = view_id;
BKE_image_user_file_path(&iuser_t, ima, name);
@@ -3662,7 +3687,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
if (!r_lock)
return NULL;
- re = RE_GetRender(iuser->scene->id.name);
+ re = RE_GetSceneRender(iuser->scene);
channels = 4;
layer = iuser->layer;
@@ -3748,7 +3773,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
}
for (rpass = rl->passes.first; rpass; rpass = rpass->next)
- if (rpass->passtype == SCE_PASS_Z)
+ if (STREQ(rpass->name, RE_PASSNAME_Z) && rpass->view_id == actview)
rectz = rpass->rect;
}
}
@@ -4129,33 +4154,32 @@ typedef struct ImagePoolEntry {
typedef struct ImagePool {
ListBase image_buffers;
+ BLI_mempool *memory_pool;
} ImagePool;
ImagePool *BKE_image_pool_new(void)
{
ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool");
+ pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolEntry), 0, 128, BLI_MEMPOOL_NOP);
return pool;
}
void BKE_image_pool_free(ImagePool *pool)
{
- ImagePoolEntry *entry, *next_entry;
-
- /* use single lock to dereference all the image buffers */
+ /* Use single lock to dereference all the image buffers. */
BLI_spin_lock(&image_spin);
-
- for (entry = pool->image_buffers.first; entry; entry = next_entry) {
- next_entry = entry->next;
-
- if (entry->ibuf)
+ for (ImagePoolEntry *entry = pool->image_buffers.first;
+ entry != NULL;
+ entry = entry->next)
+ {
+ if (entry->ibuf) {
IMB_freeImBuf(entry->ibuf);
-
- MEM_freeN(entry);
+ }
}
-
BLI_spin_unlock(&image_spin);
+ BLI_mempool_destroy(pool->memory_pool);
MEM_freeN(pool);
}
@@ -4207,7 +4231,7 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool
ibuf = image_acquire_ibuf(ima, iuser, NULL);
- entry = MEM_callocN(sizeof(ImagePoolEntry), "Image Pool Entry");
+ entry = BLI_mempool_alloc(pool->memory_pool);
entry->image = ima;
entry->frame = frame;
entry->index = index;
diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c
index 2c8399adece..1f1f4c9d341 100644
--- a/source/blender/blenkernel/intern/image_gen.c
+++ b/source/blender/blenkernel/intern/image_gen.c
@@ -132,7 +132,7 @@ static void image_buf_fill_checker_slice(unsigned char *rect,
float hsv[3] = {0.0f, 0.9f, 0.9f};
float rgb[3];
- float dark_linear_color, bright_linear_color;
+ float dark_linear_color = 0.0f, bright_linear_color = 0.0f;
if (rect_float != NULL) {
dark_linear_color = srgb_to_linearrgb(0.25f);
bright_linear_color = srgb_to_linearrgb(0.58f);
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 730d5a93758..f3a85dcee2b 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -62,6 +62,7 @@
#include "BLI_blenlib.h"
#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 6cdeaf5e59b..fd42556067e 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -38,6 +38,7 @@
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -106,7 +107,7 @@ Key *BKE_key_add(ID *id) /* common function */
Key *key;
char *el;
- key = BKE_libblock_alloc(G.main, ID_KE, "Key");
+ key = BKE_libblock_alloc(G.main, ID_KE, "Key", 0);
key->type = KEY_NORMAL;
key->from = id;
@@ -145,36 +146,48 @@ Key *BKE_key_add(ID *id) /* common function */
key->elemsize = 16;
break;
+
+ default:
+ break;
}
return key;
}
-Key *BKE_key_copy(Main *bmain, Key *key)
+/**
+ * Only copy internal data of ShapeKey ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_key_copy_data(Main *UNUSED(bmain), Key *key_dst, const Key *key_src, const int UNUSED(flag))
{
- Key *keyn;
- KeyBlock *kbn, *kb;
-
- keyn = BKE_libblock_copy(bmain, &key->id);
-
- BLI_duplicatelist(&keyn->block, &key->block);
-
- kb = key->block.first;
- kbn = keyn->block.first;
- while (kbn) {
-
- if (kbn->data) kbn->data = MEM_dupallocN(kbn->data);
- if (kb == key->refkey) keyn->refkey = kbn;
-
- kbn = kbn->next;
- kb = kb->next;
- }
+ BLI_duplicatelist(&key_dst->block, &key_src->block);
- BKE_id_copy_ensure_local(bmain, &key->id, &keyn->id);
+ KeyBlock *kb_dst, *kb_src;
+ for (kb_src = key_src->block.first, kb_dst = key_dst->block.first;
+ kb_dst;
+ kb_src = kb_src->next, kb_dst = kb_dst->next)
+ {
+ if (kb_dst->data) {
+ kb_dst->data = MEM_dupallocN(kb_dst->data);
+ }
+ if (kb_src == key_src->refkey) {
+ key_dst->refkey = kb_dst;
+ }
+ }
+}
- return keyn;
+Key *BKE_key_copy(Main *bmain, const Key *key)
+{
+ Key *key_copy;
+ BKE_id_copy_ex(bmain, &key->id, (ID **)&key_copy, 0, false);
+ return key_copy;
}
+/* XXX TODO get rid of this! */
Key *BKE_key_copy_nolib(Key *key)
{
Key *keyn;
@@ -1396,6 +1409,8 @@ Key **BKE_key_from_id_p(ID *id)
Lattice *lt = (Lattice *)id;
return &lt->key;
}
+ default:
+ break;
}
return NULL;
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index d098366aef4..e8ef346927e 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -109,42 +109,60 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name)
{
Lamp *la;
- la = BKE_libblock_alloc(bmain, ID_LA, name);
+ la = BKE_libblock_alloc(bmain, ID_LA, name, 0);
BKE_lamp_init(la);
return la;
}
-Lamp *BKE_lamp_copy(Main *bmain, Lamp *la)
+/**
+ * Only copy internal data of Lamp ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_lamp_copy_data(Main *bmain, Lamp *la_dst, const Lamp *la_src, const int flag)
{
- Lamp *lan;
- int a;
-
- lan = BKE_libblock_copy(bmain, &la->id);
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (lan->mtex[a]) {
- lan->mtex[a] = MEM_mallocN(sizeof(MTex), "copylamptex");
- memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex));
- id_us_plus((ID *)lan->mtex[a]->tex);
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (la_dst->mtex[a]) {
+ la_dst->mtex[a] = MEM_mallocN(sizeof(*la_dst->mtex[a]), __func__);
+ *la_dst->mtex[a] = *la_src->mtex[a];
}
}
-
- lan->curfalloff = curvemapping_copy(la->curfalloff);
- if (la->nodetree)
- lan->nodetree = ntreeCopyTree(bmain, la->nodetree);
+ la_dst->curfalloff = curvemapping_copy(la_src->curfalloff);
- BKE_previewimg_id_copy(&lan->id, &la->id);
+ if (la_src->nodetree) {
+ BKE_id_copy_ex(bmain, (ID *)la_src->nodetree, (ID **)&la_dst->nodetree, flag, false);
+ }
- BKE_id_copy_ensure_local(bmain, &la->id, &lan->id);
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&la_dst->id, &la_src->id);
+ }
+ else {
+ la_dst->preview = NULL;
+ }
+}
- return lan;
+Lamp *BKE_lamp_copy(Main *bmain, const Lamp *la)
+{
+ Lamp *la_copy;
+ BKE_id_copy_ex(bmain, &la->id, (ID **)&la_copy, 0, false);
+ return la_copy;
}
Lamp *localize_lamp(Lamp *la)
{
+ /* TODO replace with something like
+ * Lamp *la_copy;
+ * BKE_id_copy_ex(bmain, &la->id, (ID **)&la_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false);
+ * return la_copy;
+ *
+ * ... Once f*** nodes are fully converted to that too :( */
+
Lamp *lan;
int a;
@@ -174,15 +192,10 @@ void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool lib_local)
void BKE_lamp_free(Lamp *la)
{
- MTex *mtex;
int a;
for (a = 0; a < MAX_MTEX; a++) {
- mtex = la->mtex[a];
- if (mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
+ MEM_SAFE_FREE(la->mtex[a]);
}
BKE_animdata_free((ID *)la, false);
@@ -193,6 +206,7 @@ void BKE_lamp_free(Lamp *la)
if (la->nodetree) {
ntreeFreeTree(la->nodetree);
MEM_freeN(la->nodetree);
+ la->nodetree = NULL;
}
BKE_previewimg_free(&la->preview);
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index b0671f33094..ea4c3f380ff 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -67,7 +67,7 @@
#include "BKE_deform.h"
-/* Workaround for cyclic depenndnecy with curves.
+/* Workaround for cyclic dependency with curves.
* In such case curve_cache might not be ready yet,
*/
#define CYCLIC_DEPENDENCY_WORKAROUND
@@ -270,39 +270,46 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name)
{
Lattice *lt;
- lt = BKE_libblock_alloc(bmain, ID_LT, name);
+ lt = BKE_libblock_alloc(bmain, ID_LT, name, 0);
BKE_lattice_init(lt);
return lt;
}
-Lattice *BKE_lattice_copy(Main *bmain, Lattice *lt)
+/**
+ * Only copy internal data of Lattice ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src, const int flag)
{
- Lattice *ltn;
+ lt_dst->def = MEM_dupallocN(lt_src->def);
- ltn = BKE_libblock_copy(bmain, &lt->id);
- ltn->def = MEM_dupallocN(lt->def);
-
- if (lt->key) {
- ltn->key = BKE_key_copy(bmain, ltn->key);
- ltn->key->from = (ID *)ltn;
- }
-
- if (lt->dvert) {
- int tot = lt->pntsu * lt->pntsv * lt->pntsw;
- ltn->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
- BKE_defvert_array_copy(ltn->dvert, lt->dvert, tot);
+ if (lt_src->key) {
+ BKE_id_copy_ex(bmain, &lt_src->key->id, (ID **)&lt_dst->key, flag, false);
}
- ltn->editlatt = NULL;
+ if (lt_src->dvert) {
+ int tot = lt_src->pntsu * lt_src->pntsv * lt_src->pntsw;
+ lt_dst->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
+ BKE_defvert_array_copy(lt_dst->dvert, lt_src->dvert, tot);
+ }
- BKE_id_copy_ensure_local(bmain, &lt->id, &ltn->id);
+ lt_dst->editlatt = NULL;
+}
- return ltn;
+Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt)
+{
+ Lattice *lt_copy;
+ BKE_id_copy_ex(bmain, &lt->id, (ID **)&lt_copy, 0, false);
+ return lt_copy;
}
-/** Free (or release) any data used by this lattice (does not free the lattice itself). */
+ /** Free (or release) any data used by this lattice (does not free the lattice itself). */
void BKE_lattice_free(Lattice *lt)
{
BKE_animdata_free(&lt->id, false);
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 3411eae22e1..d5dfc63b317 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -76,6 +76,8 @@
#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
@@ -131,6 +133,12 @@
#include "atomic_ops.h"
+//#define DEBUG_TIME
+
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.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 */
@@ -263,9 +271,21 @@ void id_fake_user_clear(ID *id)
}
}
+void BKE_id_clear_newpoin(ID *id)
+{
+ if (id->newid) {
+ id->newid->tag &= ~LIB_TAG_NEW;
+ }
+ id->newid = NULL;
+}
+
static int id_expand_local_callback(
- void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag))
+ void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int cb_flag)
{
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
/* Can hapen that we get unlinkable ID here, e.g. with shapekey referring to itself (through drivers)...
* Just skip it, shape key can only be either indirectly linked, or fully local, period.
* And let's curse one more time that stupid useless shapekey ID type! */
@@ -279,18 +299,18 @@ static int id_expand_local_callback(
/**
* Expand ID usages of given id as 'extern' (and no more indirect) linked data. Used by ID copy/make_local functions.
*/
-void BKE_id_expand_local(ID *id)
+void BKE_id_expand_local(Main *bmain, ID *id)
{
- BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0);
+ BKE_library_foreach_ID_link(bmain, id, id_expand_local_callback, NULL, IDWALK_READONLY);
}
/**
* Ensure new (copied) ID is fully made local.
*/
-void BKE_id_copy_ensure_local(Main *bmain, ID *old_id, ID *new_id)
+void BKE_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id)
{
if (ID_IS_LINKED_DATABLOCK(old_id)) {
- BKE_id_expand_local(new_id);
+ BKE_id_expand_local(bmain, new_id);
BKE_id_lib_local_paths(bmain, old_id->lib, new_id);
}
}
@@ -317,7 +337,7 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
if (lib_local || is_local) {
if (!is_lib) {
id_clear_lib_data_ex(bmain, id, id_in_mainlist);
- BKE_id_expand_local(id);
+ BKE_id_expand_local(bmain, id);
}
else {
ID *id_new;
@@ -326,6 +346,17 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
if (id_copy(bmain, id, &id_new, false)) {
id_new->us = 0;
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(id, id_new);
+ Key *key = BKE_key_from_id(id), *key_new = BKE_key_from_id(id);
+ if (key && key_new) {
+ ID_NEW_SET(key, key_new);
+ }
+ bNodeTree *ntree = ntreeFromID(id), *ntree_new = ntreeFromID(id_new);
+ if (ntree && ntree_new) {
+ ID_NEW_SET(ntree, ntree_new);
+ }
+
if (!lib_local) {
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
@@ -337,6 +368,8 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
/**
* Calls the appropriate make_local method for the block, unless test is set.
*
+ * \note Always set ID->newid pointer in case it gets duplicated...
+ *
* \param lib_local Special flag used when making a whole library's content local, it needs specific handling.
*
* \return true if the block can be made local.
@@ -350,7 +383,6 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
switch ((ID_Type)GS(id->name)) {
case ID_SCE:
- /* Partially implemented (has no copy...). */
if (!test) BKE_scene_make_local(bmain, (Scene *)id, lib_local);
return true;
case ID_OB:
@@ -390,14 +422,12 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
if (!test) BKE_world_make_local(bmain, (World *)id, lib_local);
return true;
case ID_VF:
- /* Partially implemented (has no copy...). */
if (!test) BKE_vfont_make_local(bmain, (VFont *)id, lib_local);
return true;
case ID_TXT:
if (!test) BKE_text_make_local(bmain, (Text *)id, lib_local);
return true;
case ID_SO:
- /* Partially implemented (has no copy...). */
if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local);
return true;
case ID_GR:
@@ -451,116 +481,192 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
return false;
}
+struct IDCopyLibManagementData {
+ const ID *id_src;
+ ID *id_dst;
+ int flag;
+};
+
+/* Increases usercount as required, and remap self ID pointers. */
+static int id_copy_libmanagement_cb(void *user_data, ID *UNUSED(id_self), ID **id_pointer, int cb_flag)
+{
+ struct IDCopyLibManagementData *data = user_data;
+ ID *id = *id_pointer;
+
+ /* Remap self-references to new copied ID. */
+ if (id == data->id_src) {
+ /* We cannot use id_self here, it is not *always* id_dst (thanks to $£!+@#&/? nodetrees). */
+ id = *id_pointer = data->id_dst;
+ }
+
+ /* Increase used IDs refcount if needed and required. */
+ if ((data->flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && (cb_flag & IDWALK_CB_USER)) {
+ id_us_plus(id);
+ }
+
+ return IDWALK_RET_NOP;
+}
+
/**
- * Invokes the appropriate copy method for the block and returns the result in
- * newid, unless test. Returns true if the block can be copied.
+ * Generic entry point for copying a datablock (new API).
+ *
+ * \note Copy is only affecting given data-block (no ID used by copied one will be affected, besides usercount).
+ * There is only one exception, if LIB_ID_COPY_ACTIONS is defined, actions used by animdata will be duplicated.
+ *
+ * \note Usercount of new copy is always set to 1.
+ *
+ * \param bmain Main database, may be NULL only if LIB_ID_COPY_NO_MAIN is specified.
+ * \param id Source datablock.
+ * \param r_newid Pointer to new (copied) ID pointer.
+ * \param flag Set of copy options, see DNA_ID.h enum for details (leave to zero for default, full copy).
+ * \param test If set, do not do any copy, just test whether copy is supported.
+ * \return False when copying that ID type is not supported, true otherwise.
*/
-bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
+/* XXX TODO remove test thing, *all* IDs should be copyable that way! */
+bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, const bool test)
{
- if (!test) {
- *newid = NULL;
+#define LIB_ID_TYPES_NOCOPY ID_LI, ID_SCR, ID_WM, /* Not supported */ \
+ ID_IP /* Deprecated */
+
+ BLI_assert(test || (r_newid != NULL));
+ if (r_newid != NULL) {
+ *r_newid = NULL;
+ }
+ if (id == NULL) {
+ return false;
}
- /* conventions:
- * - make shallow copy, only this ID block
- * - id.us of the new ID is set to 1 */
+ if (ELEM(GS(id->name), LIB_ID_TYPES_NOCOPY)) {
+ return false;
+ }
+ else if (test) {
+ return true;
+ }
+
+ BKE_libblock_copy_ex(bmain, id, r_newid, flag);
+
switch ((ID_Type)GS(id->name)) {
+ case ID_SCE:
+ BKE_scene_copy_data(bmain, (Scene *)*r_newid, (Scene *)id, flag);
+ break;
case ID_OB:
- if (!test) *newid = (ID *)BKE_object_copy(bmain, (Object *)id);
- return true;
+ BKE_object_copy_data(bmain, (Object *)*r_newid, (Object *)id, flag);
+ break;
case ID_ME:
- if (!test) *newid = (ID *)BKE_mesh_copy(bmain, (Mesh *)id);
- return true;
+ BKE_mesh_copy_data(bmain, (Mesh *)*r_newid, (Mesh *)id, flag);
+ break;
case ID_CU:
- if (!test) *newid = (ID *)BKE_curve_copy(bmain, (Curve *)id);
- return true;
+ BKE_curve_copy_data(bmain, (Curve *)*r_newid, (Curve *)id, flag);
+ break;
case ID_MB:
- if (!test) *newid = (ID *)BKE_mball_copy(bmain, (MetaBall *)id);
- return true;
+ BKE_mball_copy_data(bmain, (MetaBall *)*r_newid, (MetaBall *)id, flag);
+ break;
case ID_MA:
- if (!test) *newid = (ID *)BKE_material_copy(bmain, (Material *)id);
- return true;
+ BKE_material_copy_data(bmain, (Material *)*r_newid, (Material *)id, flag);
+ break;
case ID_TE:
- if (!test) *newid = (ID *)BKE_texture_copy(bmain, (Tex *)id);
- return true;
+ BKE_texture_copy_data(bmain, (Tex *)*r_newid, (Tex *)id, flag);
+ break;
case ID_IM:
- if (!test) *newid = (ID *)BKE_image_copy(bmain, (Image *)id);
- return true;
+ BKE_image_copy_data(bmain, (Image *)*r_newid, (Image *)id, flag);
+ break;
case ID_LT:
- if (!test) *newid = (ID *)BKE_lattice_copy(bmain, (Lattice *)id);
- return true;
+ BKE_lattice_copy_data(bmain, (Lattice *)*r_newid, (Lattice *)id, flag);
+ break;
case ID_LA:
- if (!test) *newid = (ID *)BKE_lamp_copy(bmain, (Lamp *)id);
- return true;
+ BKE_lamp_copy_data(bmain, (Lamp *)*r_newid, (Lamp *)id, flag);
+ break;
case ID_SPK:
- if (!test) *newid = (ID *)BKE_speaker_copy(bmain, (Speaker *)id);
- return true;
+ BKE_speaker_copy_data(bmain, (Speaker *)*r_newid, (Speaker *)id, flag);
+ break;
case ID_CA:
- if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id);
- return true;
+ BKE_camera_copy_data(bmain, (Camera *)*r_newid, (Camera *)id, flag);
+ break;
case ID_KE:
- if (!test) *newid = (ID *)BKE_key_copy(bmain, (Key *)id);
- return true;
+ BKE_key_copy_data(bmain, (Key *)*r_newid, (Key *)id, flag);
+ break;
case ID_WO:
- if (!test) *newid = (ID *)BKE_world_copy(bmain, (World *)id);
- return true;
+ BKE_world_copy_data(bmain, (World *)*r_newid, (World *)id, flag);
+ break;
case ID_TXT:
- if (!test) *newid = (ID *)BKE_text_copy(bmain, (Text *)id);
- return true;
+ BKE_text_copy_data(bmain, (Text *)*r_newid, (Text *)id, flag);
+ break;
case ID_GR:
- if (!test) *newid = (ID *)BKE_group_copy(bmain, (Group *)id);
- return true;
+ BKE_group_copy_data(bmain, (Group *)*r_newid, (Group *)id, flag);
+ break;
case ID_AR:
- if (!test) *newid = (ID *)BKE_armature_copy(bmain, (bArmature *)id);
- return true;
+ BKE_armature_copy_data(bmain, (bArmature *)*r_newid, (bArmature *)id, flag);
+ break;
case ID_AC:
- if (!test) *newid = (ID *)BKE_action_copy(bmain, (bAction *)id);
- return true;
+ BKE_action_copy_data(bmain, (bAction *)*r_newid, (bAction *)id, flag);
+ break;
case ID_NT:
- if (!test) *newid = (ID *)ntreeCopyTree(bmain, (bNodeTree *)id);
- return true;
+ BKE_node_tree_copy_data(bmain, (bNodeTree *)*r_newid, (bNodeTree *)id, flag);
+ break;
case ID_BR:
- if (!test) *newid = (ID *)BKE_brush_copy(bmain, (Brush *)id);
- return true;
+ BKE_brush_copy_data(bmain, (Brush *)*r_newid, (Brush *)id, flag);
+ break;
case ID_PA:
- if (!test) *newid = (ID *)BKE_particlesettings_copy(bmain, (ParticleSettings *)id);
- return true;
+ BKE_particlesettings_copy_data(bmain, (ParticleSettings *)*r_newid, (ParticleSettings *)id, flag);
+ break;
case ID_GD:
- if (!test) *newid = (ID *)BKE_gpencil_data_duplicate(bmain, (bGPdata *)id, false);
- return true;
+ BKE_gpencil_copy_data(bmain, (bGPdata *)*r_newid, (bGPdata *)id, flag);
+ break;
case ID_MC:
- if (!test) *newid = (ID *)BKE_movieclip_copy(bmain, (MovieClip *)id);
- return true;
+ BKE_movieclip_copy_data(bmain, (MovieClip *)*r_newid, (MovieClip *)id, flag);
+ break;
case ID_MSK:
- if (!test) *newid = (ID *)BKE_mask_copy(bmain, (Mask *)id);
- return true;
+ BKE_mask_copy_data(bmain, (Mask *)*r_newid, (Mask *)id, flag);
+ break;
case ID_LS:
- if (!test) *newid = (ID *)BKE_linestyle_copy(bmain, (FreestyleLineStyle *)id);
- return true;
+ BKE_linestyle_copy_data(bmain, (FreestyleLineStyle *)*r_newid, (FreestyleLineStyle *)id, flag);
+ break;
case ID_PAL:
- if (!test) *newid = (ID *)BKE_palette_copy(bmain, (Palette *)id);
- return true;
+ BKE_palette_copy_data(bmain, (Palette *)*r_newid, (Palette *)id, flag);
+ break;
case ID_PC:
- if (!test) *newid = (ID *)BKE_paint_curve_copy(bmain, (PaintCurve *)id);
- return true;
+ BKE_paint_curve_copy_data(bmain, (PaintCurve *)*r_newid, (PaintCurve *)id, flag);
+ break;
case ID_CF:
- if (!test) *newid = (ID *)BKE_cachefile_copy(bmain, (CacheFile *)id);
- return true;
- case ID_SCE:
+ BKE_cachefile_copy_data(bmain, (CacheFile *)*r_newid, (CacheFile *)id, flag);
+ break;
+ case ID_SO:
+ BKE_sound_copy_data(bmain, (bSound *)*r_newid, (bSound *)id, flag);
+ break;
+ case ID_VF:
+ BKE_vfont_copy_data(bmain, (VFont *)*r_newid, (VFont *)id, flag);
+ break;
case ID_LI:
case ID_SCR:
case ID_WM:
- return false; /* can't be copied from here */
- case ID_VF:
- case ID_SO:
- return false; /* not implemented */
case ID_IP:
- return false; /* deprecated */
+ BLI_assert(0); /* Should have been rejected at start of function! */
+ break;
}
-
- return false;
+
+ /* Update ID refcount, remap pointers to self in new ID. */
+ struct IDCopyLibManagementData data = {.id_src = id, .id_dst = *r_newid, .flag = flag};
+ BKE_library_foreach_ID_link(bmain, *r_newid, id_copy_libmanagement_cb, &data, IDWALK_NOP);
+
+ /* Do not make new copy local in case we are copying outside of main...
+ * XXX TODO: is this behavior OK, or should we need own flag to control that? */
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ BKE_id_copy_ensure_local(bmain, id, *r_newid);
+ }
+
+ return true;
+}
+
+/**
+ * Invokes the appropriate copy method for the block and returns the result in
+ * newid, unless test. Returns true if the block can be copied.
+ */
+bool id_copy(Main *bmain, const ID *id, ID **newid, bool test)
+{
+ return BKE_id_copy_ex(bmain, id, newid, 0, test);
}
+/** Does *not* set ID->newid pointer. */
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
ID *newid = NULL;
@@ -571,11 +677,11 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
if (RNA_property_editable(ptr, prop)) {
if (id_copy(CTX_data_main(C), id, &newid, false) && newid) {
/* copy animation actions too */
- BKE_animdata_copy_id_action(id);
+ BKE_animdata_copy_id_action(id, false);
/* us is 1 by convention, but RNA_property_pointer_set
* will also increment it, so set it to zero */
newid->us = 0;
-
+
/* assign copy */
RNA_id_pointer_create(newid, &idptr);
RNA_property_pointer_set(ptr, prop, idptr);
@@ -589,6 +695,101 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
return false;
}
+static int libblock_management_us_plus(void *UNUSED(user_data), ID *UNUSED(id_self), ID **id_pointer, int cb_flag)
+{
+ if (cb_flag & IDWALK_CB_USER) {
+ id_us_plus(*id_pointer);
+ }
+ if (cb_flag & IDWALK_CB_USER_ONE) {
+ id_us_ensure_real(*id_pointer);
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+static int libblock_management_us_min(void *UNUSED(user_data), ID *UNUSED(id_self), ID **id_pointer, int cb_flag)
+{
+ if (cb_flag & IDWALK_CB_USER) {
+ id_us_min(*id_pointer);
+ }
+ /* We can do nothing in IDWALK_CB_USER_ONE case! */
+
+ return IDWALK_RET_NOP;
+}
+
+/** Add a 'NO_MAIN' datablock to given main (also sets usercounts of its IDs if needed). */
+void BKE_libblock_management_main_add(Main *bmain, void *idv)
+{
+ ID *id = idv;
+
+ BLI_assert(bmain != NULL);
+ if ((id->tag & LIB_TAG_NO_MAIN) == 0) {
+ return;
+ }
+
+ if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) {
+ /* We cannot add non-allocated ID to Main! */
+ return;
+ }
+
+ /* We cannot allow non-userrefcounting IDs in Main database! */
+ if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) {
+ BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, NULL, IDWALK_NOP);
+ }
+
+ ListBase *lb = which_libbase(bmain, GS(id->name));
+ BKE_main_lock(bmain);
+ BLI_addtail(lb, id);
+ new_id(lb, id, NULL);
+ /* alphabetic insertion: is in new_id */
+ id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT);
+ BKE_main_unlock(bmain);
+}
+
+/** Remove a datablock from given main (set it to 'NO_MAIN' status). */
+void BKE_libblock_management_main_remove(Main *bmain, void *idv)
+{
+ ID *id = idv;
+
+ BLI_assert(bmain != NULL);
+ if ((id->tag & LIB_TAG_NO_MAIN) != 0) {
+ return;
+ }
+
+ /* For now, allow userrefcounting IDs to get out of Main - can be handy in some cases... */
+
+ ListBase *lb = which_libbase(bmain, GS(id->name));
+ BKE_main_lock(bmain);
+ BLI_remlink(lb, id);
+ id->tag |= LIB_TAG_NO_MAIN;
+ BKE_main_unlock(bmain);
+}
+
+void BKE_libblock_management_usercounts_set(Main *bmain, void *idv)
+{
+ ID *id = idv;
+
+ if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) == 0) {
+ return;
+ }
+
+ BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, NULL, IDWALK_NOP);
+ id->tag &= ~LIB_TAG_NO_USER_REFCOUNT;
+}
+
+void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv)
+{
+ ID *id = idv;
+
+ /* We do not allow IDs in Main database to not be userrefcounting. */
+ if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0 || (id->tag & LIB_TAG_NO_MAIN) != 0) {
+ return;
+ }
+
+ BKE_library_foreach_ID_link(bmain, id, libblock_management_us_min, NULL, IDWALK_NOP);
+ id->tag |= LIB_TAG_NO_USER_REFCOUNT;
+}
+
ListBase *which_libbase(Main *mainlib, short type)
{
switch ((ID_Type)type) {
@@ -824,118 +1025,72 @@ int set_listbasepointers(Main *main, ListBase **lb)
* **************************** */
/**
+ * Get allocation size fo a given datablock type and optionally allocation name.
+ */
+size_t BKE_libblock_get_alloc_info(short type, const char **name)
+{
+#define CASE_RETURN(id_code, type) \
+ case id_code: \
+ do { \
+ if (name != NULL) { \
+ *name = #type; \
+ } \
+ return sizeof(type); \
+ } while(0)
+
+ switch ((ID_Type)type) {
+ CASE_RETURN(ID_SCE, Scene);
+ CASE_RETURN(ID_LI, Library);
+ CASE_RETURN(ID_OB, Object);
+ CASE_RETURN(ID_ME, Mesh);
+ CASE_RETURN(ID_CU, Curve);
+ CASE_RETURN(ID_MB, MetaBall);
+ CASE_RETURN(ID_MA, Material);
+ CASE_RETURN(ID_TE, Tex);
+ CASE_RETURN(ID_IM, Image);
+ CASE_RETURN(ID_LT, Lattice);
+ CASE_RETURN(ID_LA, Lamp);
+ CASE_RETURN(ID_CA, Camera);
+ CASE_RETURN(ID_IP, Ipo);
+ CASE_RETURN(ID_KE, Key);
+ CASE_RETURN(ID_WO, World);
+ CASE_RETURN(ID_SCR, bScreen);
+ CASE_RETURN(ID_VF, VFont);
+ CASE_RETURN(ID_TXT, Text);
+ CASE_RETURN(ID_SPK, Speaker);
+ CASE_RETURN(ID_SO, bSound);
+ CASE_RETURN(ID_GR, Group);
+ CASE_RETURN(ID_AR, bArmature);
+ CASE_RETURN(ID_AC, bAction);
+ CASE_RETURN(ID_NT, bNodeTree);
+ CASE_RETURN(ID_BR, Brush);
+ CASE_RETURN(ID_PA, ParticleSettings);
+ CASE_RETURN(ID_WM, wmWindowManager);
+ CASE_RETURN(ID_GD, bGPdata);
+ CASE_RETURN(ID_MC, MovieClip);
+ CASE_RETURN(ID_MSK, Mask);
+ CASE_RETURN(ID_LS, FreestyleLineStyle);
+ CASE_RETURN(ID_PAL, Palette);
+ CASE_RETURN(ID_PC, PaintCurve);
+ CASE_RETURN(ID_CF, CacheFile);
+ }
+ return 0;
+#undef CASE_RETURN
+}
+
+/**
* Allocates and returns memory of the right size for the specified block type,
* initialized to zero.
*/
void *BKE_libblock_alloc_notest(short type)
{
- ID *id = NULL;
-
- switch ((ID_Type)type) {
- case ID_SCE:
- id = MEM_callocN(sizeof(Scene), "scene");
- break;
- case ID_LI:
- id = MEM_callocN(sizeof(Library), "library");
- break;
- case ID_OB:
- id = MEM_callocN(sizeof(Object), "object");
- break;
- case ID_ME:
- id = MEM_callocN(sizeof(Mesh), "mesh");
- break;
- case ID_CU:
- id = MEM_callocN(sizeof(Curve), "curve");
- break;
- case ID_MB:
- id = MEM_callocN(sizeof(MetaBall), "mball");
- break;
- case ID_MA:
- id = MEM_callocN(sizeof(Material), "mat");
- break;
- case ID_TE:
- id = MEM_callocN(sizeof(Tex), "tex");
- break;
- case ID_IM:
- id = MEM_callocN(sizeof(Image), "image");
- break;
- case ID_LT:
- id = MEM_callocN(sizeof(Lattice), "latt");
- break;
- case ID_LA:
- id = MEM_callocN(sizeof(Lamp), "lamp");
- break;
- case ID_CA:
- id = MEM_callocN(sizeof(Camera), "camera");
- break;
- case ID_IP:
- id = MEM_callocN(sizeof(Ipo), "ipo");
- break;
- case ID_KE:
- id = MEM_callocN(sizeof(Key), "key");
- break;
- case ID_WO:
- id = MEM_callocN(sizeof(World), "world");
- break;
- case ID_SCR:
- id = MEM_callocN(sizeof(bScreen), "screen");
- break;
- case ID_VF:
- id = MEM_callocN(sizeof(VFont), "vfont");
- break;
- case ID_TXT:
- id = MEM_callocN(sizeof(Text), "text");
- break;
- case ID_SPK:
- id = MEM_callocN(sizeof(Speaker), "speaker");
- break;
- case ID_SO:
- id = MEM_callocN(sizeof(bSound), "sound");
- break;
- case ID_GR:
- id = MEM_callocN(sizeof(Group), "group");
- break;
- case ID_AR:
- id = MEM_callocN(sizeof(bArmature), "armature");
- break;
- case ID_AC:
- id = MEM_callocN(sizeof(bAction), "action");
- break;
- case ID_NT:
- id = MEM_callocN(sizeof(bNodeTree), "nodetree");
- break;
- case ID_BR:
- id = MEM_callocN(sizeof(Brush), "brush");
- break;
- case ID_PA:
- id = MEM_callocN(sizeof(ParticleSettings), "ParticleSettings");
- break;
- case ID_WM:
- id = MEM_callocN(sizeof(wmWindowManager), "Window manager");
- break;
- case ID_GD:
- id = MEM_callocN(sizeof(bGPdata), "Grease Pencil");
- break;
- case ID_MC:
- id = MEM_callocN(sizeof(MovieClip), "Movie Clip");
- break;
- case ID_MSK:
- id = MEM_callocN(sizeof(Mask), "Mask");
- break;
- case ID_LS:
- id = MEM_callocN(sizeof(FreestyleLineStyle), "Freestyle Line Style");
- break;
- case ID_PAL:
- id = MEM_callocN(sizeof(Palette), "Palette");
- break;
- case ID_PC:
- id = MEM_callocN(sizeof(PaintCurve), "Paint Curve");
- break;
- case ID_CF:
- id = MEM_callocN(sizeof(CacheFile), "Cache File");
- break;
+ const char *name;
+ size_t size = BKE_libblock_get_alloc_info(type, &name);
+ if (size != 0) {
+ return MEM_callocN(size, name);
}
- return id;
+ BLI_assert(!"Request to allocate unknown data type");
+ return NULL;
}
/**
@@ -944,23 +1099,44 @@ void *BKE_libblock_alloc_notest(short type)
* The user count is set to 1, all other content (apart from name and links) being
* initialized to zero.
*/
-void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
+void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int flag)
{
- ID *id = NULL;
- ListBase *lb = which_libbase(bmain, type);
-
- id = BKE_libblock_alloc_notest(type);
+ BLI_assert((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
+
+ ID *id = BKE_libblock_alloc_notest(type);
+
if (id) {
- BKE_main_lock(bmain);
- BLI_addtail(lb, id);
- id->us = 1;
+ if ((flag & LIB_ID_CREATE_NO_MAIN) != 0) {
+ id->tag |= LIB_TAG_NO_MAIN;
+ }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0) {
+ id->tag |= LIB_TAG_NO_USER_REFCOUNT;
+ }
+
id->icon_id = 0;
- *( (short *)id->name) = type;
- new_id(lb, id, name);
- /* alphabetic insertion: is in new_id */
- BKE_main_unlock(bmain);
+ *((short *)id->name) = type;
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id->us = 1;
+ }
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ ListBase *lb = which_libbase(bmain, type);
+
+ BKE_main_lock(bmain);
+ BLI_addtail(lb, id);
+ new_id(lb, id, name);
+ /* alphabetic insertion: is in new_id */
+ BKE_main_unlock(bmain);
+
+ /* TODO to be removed from here! */
+ if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) {
+ DAG_id_type_tag(bmain, type);
+ }
+ }
+ else {
+ BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2);
+ }
}
- DAG_id_type_tag(bmain, type);
+
return id;
}
@@ -1083,102 +1259,82 @@ void BKE_libblock_init_empty(ID *id)
/* by spec, animdata is first item after ID */
/* and, trust that BKE_animdata_from_id() will only find AnimData for valid ID-types */
-static void id_copy_animdata(ID *id, const bool do_action)
+static void id_copy_animdata(Main *bmain, ID *id, const bool do_action)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
- iat->adt = BKE_animdata_copy(iat->adt, do_action); /* could be set to false, need to investigate */
+ iat->adt = BKE_animdata_copy(bmain, iat->adt, do_action); /* could be set to false, need to investigate */
}
}
-/* material nodes use this since they are not treated as libdata */
-void BKE_libblock_copy_data(ID *id, const ID *id_from, const bool do_action)
+void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
{
- if (id_from->properties)
- id->properties = IDP_CopyProperty(id_from->properties);
-
- /* the duplicate should get a copy of the animdata */
- id_copy_animdata(id, do_action);
-}
+ ID *new_id = *r_newid;
+
+ /* Grrrrrrrrr... Not adding 'root' nodetrees to bmain.... grrrrrrrrrrrrrrrrrrrr! */
+ /* This is taken from original ntree copy code, might be weak actually? */
+ const bool use_nodetree_alloc_exception = ((GS(id->name) == ID_NT) && (bmain != NULL) &&
+ (BLI_findindex(&bmain->nodetree, id) < 0));
+
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL);
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0);
+
+ if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) {
+ /* r_newid already contains pointer to allocated memory. */
+ /* TODO do we want to memset(0) whole mem before filling it? */
+ BLI_strncpy(new_id->name, id->name, sizeof(new_id->name));
+ new_id->us = 0;
+ new_id->tag |= LIB_TAG_NOT_ALLOCATED | LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT;
+ /* TODO Do we want/need to copy more from ID struct itself? */
+ }
+ else {
+ new_id = BKE_libblock_alloc(bmain, GS(id->name), id->name + 2, flag | (use_nodetree_alloc_exception ? LIB_ID_CREATE_NO_MAIN : 0));
+ }
+ BLI_assert(new_id != NULL);
-/* used everywhere in blenkernel */
-void *BKE_libblock_copy(Main *bmain, ID *id)
-{
- ID *idn;
- size_t idn_len;
+ const size_t id_len = BKE_libblock_get_alloc_info(GS(new_id->name), NULL);
+ const size_t id_offset = sizeof(ID);
+ if ((int)id_len - (int)id_offset > 0) { /* signed to allow neg result */ /* XXX ????? */
+ const char *cp = (const char *)id;
+ char *cpn = (char *)new_id;
- idn = BKE_libblock_alloc(bmain, GS(id->name), id->name + 2);
+ memcpy(cpn + id_offset, cp + id_offset, id_len - id_offset);
+ }
- assert(idn != NULL);
+ if (id->properties) {
+ new_id->properties = IDP_CopyProperty_ex(id->properties, flag);
+ }
- idn_len = MEM_allocN_len(idn);
- if ((int)idn_len - (int)sizeof(ID) > 0) { /* signed to allow neg result */
- const char *cp = (const char *)id;
- char *cpn = (char *)idn;
+ /* the duplicate should get a copy of the animdata */
+ id_copy_animdata(bmain, new_id, (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0);
- memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID));
+ if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ DAG_id_type_tag(bmain, GS(new_id->name));
}
-
- id->newid = idn;
- idn->tag |= LIB_TAG_NEW;
- BKE_libblock_copy_data(idn, id, false);
-
- return idn;
+ *r_newid = new_id;
}
-void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
+/* used everywhere in blenkernel */
+void *BKE_libblock_copy(Main *bmain, const ID *id)
{
ID *idn;
- size_t idn_len;
-
- idn = BKE_libblock_alloc_notest(GS(id->name));
- assert(idn != NULL);
-
- BLI_strncpy(idn->name, id->name, sizeof(idn->name));
- idn_len = MEM_allocN_len(idn);
- if ((int)idn_len - (int)sizeof(ID) > 0) { /* signed to allow neg result */
- const char *cp = (const char *)id;
- char *cpn = (char *)idn;
-
- memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID));
- }
-
- id->newid = idn;
- idn->tag |= LIB_TAG_NEW;
- idn->us = 1;
-
- BKE_libblock_copy_data(idn, id, do_action);
+ BKE_libblock_copy_ex(bmain, id, &idn, 0);
return idn;
}
-static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag)
+void *BKE_libblock_copy_nolib(const ID *id, const bool do_action)
{
- ID *id = *id_pointer;
- if (id) {
- /* See: NEW_ID macro */
- if (id->newid) {
- BKE_library_update_ID_link_user(id->newid, id, cd_flag);
- *id_pointer = id->newid;
- }
- else if (id->tag & LIB_TAG_NEW) {
- id->tag &= ~LIB_TAG_NEW;
- BKE_libblock_relink(id);
- }
- }
- return IDWALK_RET_NOP;
-}
+ ID *idn;
-void BKE_libblock_relink(ID *id)
-{
- if (ID_IS_LINKED_DATABLOCK(id))
- return;
+ BKE_libblock_copy_ex(NULL, id, &idn, LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | (do_action ? LIB_ID_COPY_ACTIONS : 0));
- BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
+ return idn;
}
void BKE_library_free(Library *lib)
@@ -1259,6 +1415,10 @@ void BKE_main_free(Main *mainvar)
}
}
+ if (mainvar->relations) {
+ BKE_main_relations_free(mainvar);
+ }
+
BLI_spin_end((SpinLock *)mainvar->lock);
MEM_freeN(mainvar->lock);
DEG_evaluation_context_free(mainvar->eval_ctx);
@@ -1275,6 +1435,78 @@ void BKE_main_unlock(struct Main *bmain)
BLI_spin_unlock((SpinLock *) bmain->lock);
}
+
+static int main_relations_create_cb(void *user_data, ID *id_self, ID **id_pointer, int cb_flag)
+{
+ MainIDRelations *rel = user_data;
+
+ if (*id_pointer) {
+ MainIDRelationsEntry *entry, **entry_p;
+
+ entry = BLI_mempool_alloc(rel->entry_pool);
+ if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) {
+ entry->next = *entry_p;
+ }
+ else {
+ entry->next = NULL;
+ }
+ entry->id_pointer = id_pointer;
+ entry->usage_flag = cb_flag;
+ *entry_p = entry;
+
+ entry = BLI_mempool_alloc(rel->entry_pool);
+ if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) {
+ entry->next = *entry_p;
+ }
+ else {
+ entry->next = NULL;
+ }
+ entry->id_pointer = (ID **)id_self;
+ entry->usage_flag = cb_flag;
+ *entry_p = entry;
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/** Generate the mappings between used IDs and their users, and vice-versa. */
+void BKE_main_relations_create(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a;
+
+ if (bmain->relations != NULL) {
+ BKE_main_relations_free(bmain);
+ }
+
+ bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__);
+ bmain->relations->id_used_to_user = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ bmain->relations->id_user_to_used = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ bmain->relations->entry_pool = BLI_mempool_create(sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP);
+
+ for (a = set_listbasepointers(bmain, lbarray); a--; ) {
+ for (id = lbarray[a]->first; id; id = id->next) {
+ BKE_library_foreach_ID_link(NULL, id, main_relations_create_cb, bmain->relations, IDWALK_READONLY);
+ }
+ }
+}
+
+void BKE_main_relations_free(Main *bmain)
+{
+ if (bmain->relations) {
+ if (bmain->relations->id_used_to_user) {
+ BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL);
+ }
+ if (bmain->relations->id_user_to_used) {
+ BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL);
+ }
+ BLI_mempool_destroy(bmain->relations->entry_pool);
+ MEM_freeN(bmain->relations);
+ bmain->relations = NULL;
+ }
+}
+
/**
* Generates a raw .blend file thumbnail data from given image.
*
@@ -1415,7 +1647,8 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name)
static bool check_for_dupid(ListBase *lb, ID *id, char *name)
{
ID *idtest;
- int nr = 0, a, left_len;
+ int nr = 0, a;
+ size_t left_len;
#define MAX_IN_USE 64
bool in_use[MAX_IN_USE];
/* to speed up finding unused numbers within [1 .. MAX_IN_USE - 1] */
@@ -1439,14 +1672,18 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
/* if new name will be too long, truncate it */
if (nr > 999 && left_len > (MAX_ID_NAME - 8)) { /* assumption: won't go beyond 9999 */
- left[MAX_ID_NAME - 8] = 0;
+ left[MAX_ID_NAME - 8] = '\0';
left_len = MAX_ID_NAME - 8;
}
else if (left_len > (MAX_ID_NAME - 7)) {
- left[MAX_ID_NAME - 7] = 0;
+ left[MAX_ID_NAME - 7] = '\0';
left_len = MAX_ID_NAME - 7;
}
+ /* Code above may have generated invalid utf-8 string, due to raw truncation.
+ * Ensure we get a valid one now! */
+ left_len -= (size_t)BLI_utf8_invalid_strip(left, left_len);
+
for (idtest = lb->first; idtest; idtest = idtest->next) {
int nrtest;
if ( (id != idtest) &&
@@ -1487,7 +1724,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
* shave off the end chars until we have a unique name.
* Check the null terminators match as well so we don't get Cube.000 -> Cube.00 */
if (nr == 0 && name[left_len] == '\0') {
- int len;
+ size_t len;
/* FIXME: this code will never be executed, because either nr will be
* at least 1, or name will not end at left_len! */
BLI_assert(0);
@@ -1625,6 +1862,62 @@ void BKE_main_id_clear_newpoins(Main *bmain)
}
}
+
+static void library_make_local_copying_check(ID *id, GSet *loop_tags, MainIDRelations *id_relations, GSet *done_ids)
+{
+ if (BLI_gset_haskey(done_ids, id)) {
+ return; /* Already checked, nothing else to do. */
+ }
+
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->id_used_to_user, id);
+ BLI_gset_insert(loop_tags, id);
+ for (; entry != NULL; entry = entry->next) {
+ ID *par_id = (ID *)entry->id_pointer; /* used_to_user stores ID pointer, not pointer to ID pointer... */
+
+ /* Our oh-so-beloved 'from' pointers... */
+ if (entry->usage_flag & IDWALK_CB_LOOPBACK) {
+ /* We totally disregard Object->proxy_from 'usage' here, this one would only generate fake positives. */
+ if (GS(par_id->name) == ID_OB) {
+ BLI_assert(((Object *)par_id)->proxy_from == (Object *)id);
+ continue;
+ }
+
+ /* Shapekeys are considered 'private' to their owner ID here, and never tagged (since they cannot be linked),
+ * so we have to switch effective parent to their owner. */
+ if (GS(par_id->name) == ID_KE) {
+ par_id = ((Key *)par_id)->from;
+ }
+ }
+
+ if (par_id->lib == NULL) {
+ /* Local user, early out to avoid some gset querying... */
+ continue;
+ }
+ if (!BLI_gset_haskey(done_ids, par_id)) {
+ if (BLI_gset_haskey(loop_tags, par_id)) {
+ /* We are in a 'dependency loop' of IDs, this does not say us anything, skip it.
+ * Note that this is the situation that can lead to archipelagoes of linked data-blocks
+ * (since all of them have non-local users, they would all be duplicated, leading to a loop of unused
+ * linked data-blocks that cannot be freed since they all use each other...). */
+ continue;
+ }
+ /* Else, recursively check that user ID. */
+ library_make_local_copying_check(par_id, loop_tags, id_relations, done_ids);
+ }
+
+ if (par_id->tag & LIB_TAG_DOIT) {
+ /* This user will be fully local in future, so far so good, nothing to do here but check next user. */
+ }
+ else {
+ /* This user won't be fully local in future, so current ID won't be either. And we are done checking it. */
+ id->tag &= ~LIB_TAG_DOIT;
+ break;
+ }
+ }
+ BLI_gset_add(done_ids, id);
+ BLI_gset_remove(loop_tags, id, NULL);
+}
+
/** Make linked datablocks local.
*
* \param bmain Almost certainly G.main.
@@ -1635,11 +1928,10 @@ void BKE_main_id_clear_newpoins(Main *bmain)
/* Note: Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether
* they were also indirectly used or not...
*
- * Current version uses regular id_make_local callback, which is not super-efficient since this ends up
- * duplicating some IDs and then removing original ones (due to missing knowledge of which ID uses some other ID).
- *
- * However, we now have a first check that allows us to use 'direct localization' of a lot of IDs, so performances
- * are now *reasonably* OK.
+ * Current version uses regular id_make_local callback, with advanced pre-processing step to detect all cases of
+ * IDs currently indirectly used, but which will be used by local data only once this function is finished.
+ * This allows to avoid any uneeded duplication of IDs, and hence all time lost afterwards to remove
+ * orphaned linked data-blocks...
*/
void BKE_library_make_local(
Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake)
@@ -1650,9 +1942,21 @@ void BKE_library_make_local(
LinkNode *todo_ids = NULL;
LinkNode *copied_ids = NULL;
- LinkNode *linked_loop_candidates = NULL;
MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__);
+ GSet *done_ids = BLI_gset_ptr_new(__func__);
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(make_local);
+#endif
+
+ BKE_main_relations_create(bmain);
+
+#ifdef DEBUG_TIME
+ printf("Pre-compute current ID relations: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
/* Step 1: Detect datablocks to make local. */
for (a = set_listbasepointers(bmain, lbarray); a--; ) {
id = lbarray[a]->first;
@@ -1662,17 +1966,25 @@ void BKE_library_make_local(
const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
for (; id; id = id->next) {
- id->newid = NULL;
+ ID *ntree = (ID *)ntreeFromID(id);
+
id->tag &= ~LIB_TAG_DOIT;
+ if (ntree != NULL) {
+ ntree->tag &= ~LIB_TAG_DOIT;
+ }
if (id->lib == NULL) {
id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
}
- /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its
- * possible to tag data you don't want to be made local, used for
- * appending data, so any libdata already linked wont become local
- * (very nasty to discover all your links are lost after appending).
+ /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its possible to tag data you don't want to
+ * be made local, used for appending data, so any libdata already linked wont become local (very nasty
+ * to discover all your links are lost after appending).
* Also, never ever make proxified objects local, would not make any sense. */
+ /* Some more notes:
+ * - Shapekeys are never tagged here (since they are not linkable).
+ * - Nodetrees used in materials etc. have to be tagged manually, since they do not exist in Main (!).
+ * This is ok-ish on 'make local' side of things (since those are handled by their 'owner' IDs),
+ * but complicates slightly the pre-processing of relations between IDs at step 2... */
else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
ELEM(lib, NULL, id->lib) &&
!(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) &&
@@ -1680,13 +1992,42 @@ void BKE_library_make_local(
{
BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem);
id->tag |= LIB_TAG_DOIT;
+
+ /* Tag those nasty non-ID nodetrees, but do not add them to todo list, making them local is handled
+ * by 'owner' ID. This is needed for library_make_local_copying_check() to work OK at step 2. */
+ if (ntree != NULL) {
+ ntree->tag |= LIB_TAG_DOIT;
+ }
+ }
+ else {
+ /* Linked ID that we won't be making local (needed info for step 2, see below). */
+ BLI_gset_add(done_ids, id);
}
}
}
+#ifdef DEBUG_TIME
+ printf("Step 1: Detect datablocks to make local: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
/* Step 2: Check which datablocks we can directly make local (because they are only used by already, or future,
- * local data), others will need to be duplicated and further processed later. */
- BKE_library_indirectly_used_data_tag_clear(bmain);
+ * local data), others will need to be duplicated. */
+ GSet *loop_tags = BLI_gset_ptr_new(__func__);
+ for (LinkNode *it = todo_ids; it; it = it->next) {
+ library_make_local_copying_check(it->link, loop_tags, bmain->relations, done_ids);
+ BLI_assert(BLI_gset_size(loop_tags) == 0);
+ }
+ BLI_gset_free(loop_tags, NULL);
+ BLI_gset_free(done_ids, NULL);
+
+ /* Next step will most likely add new IDs, better to get rid of this mapping now. */
+ BKE_main_relations_free(bmain);
+
+#ifdef DEBUG_TIME
+ printf("Step 2: Check which datablocks we can directly make local: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
/* Step 3: Make IDs local, either directly (quick and simple), or using generic process,
* which involves more complex checks and might instead create a local copy of original linked ID. */
@@ -1696,10 +2037,10 @@ void BKE_library_make_local(
if (id->tag & LIB_TAG_DOIT) {
/* We know all users of this object are local or will be made fully local, even if currently there are
- * some indirect usages. So instead of making a copy that se'll likely get rid of later, directly make
+ * some indirect usages. So instead of making a copy that we'll likely get rid of later, directly make
* that data block local. Saves a tremendous amount of time with complex scenes... */
id_clear_lib_data_ex(bmain, id, true);
- BKE_id_expand_local(id);
+ BKE_id_expand_local(bmain, id);
id->tag &= ~LIB_TAG_DOIT;
}
else {
@@ -1708,7 +2049,7 @@ void BKE_library_make_local(
/* Special case for objects because we don't want proxy pointers to be
* cleared yet. This will happen down the road in this function.
*/
- BKE_object_make_local_ex(bmain, (Object*)id, true, false);
+ BKE_object_make_local_ex(bmain, (Object *)id, true, false);
}
else {
id_make_local(bmain, id, false, true);
@@ -1728,13 +2069,21 @@ void BKE_library_make_local(
}
}
+#ifdef DEBUG_TIME
+ printf("Step 3: Make IDs local: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
/* At this point, we are done with directly made local IDs. Now we have to handle duplicated ones, since their
* remaining linked original counterpart may not be needed anymore... */
todo_ids = NULL;
- /* Step 4: We have to remap local usages of old (linked) ID to new (local) id in a separated loop,
+ /* Step 4: We have to remap local usages of old (linked) ID to new (local) ID in a separated loop,
* as lbarray ordering is not enough to ensure us we did catch all dependencies
* (e.g. if making local a parent object before its child...). See T48907. */
+ /* TODO This is now the biggest step by far (in term of processing time). We may be able to gain here by
+ * using again main->relations mapping, but... this implies BKE_libblock_remap & co to be able to update
+ * main->relations on the fly. Have to think about it a bit more, and see whether new code is OK first, anyway. */
for (LinkNode *it = copied_ids; it; it = it->next) {
id = it->link;
@@ -1753,6 +2102,64 @@ void BKE_library_make_local(
}
}
+#ifdef DEBUG_TIME
+ printf("Step 4: Remap local usages of old (linked) ID to new (local) ID: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+ /* Note: Keeping both version of the code (old one being safer, since it still has checks against unused IDs)
+ * for now, we can remove old one once it has been tested for some time in master... */
+#if 1
+ /* Step 5: proxy 'remapping' hack. */
+ for (LinkNode *it = copied_ids; it; it = it->next) {
+ /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
+ * from another blend file into this one, even when that blend file contains proxified
+ * armatures that have local references. Since the proxified object needs to be linked
+ * (not local), this will only work when the "Localize all" checkbox is disabled.
+ * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
+ if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
+ Object *ob = (Object *)id;
+ Object *ob_new = (Object *)id->newid;
+ bool is_local = false, is_lib = false;
+
+ /* Proxies only work when the proxified object is linked-in from a library. */
+ if (ob->proxy->id.lib == NULL) {
+ printf("Warning, proxy object %s will loose its link to %s, because the "
+ "proxified object is local.\n", id->newid->name, ob->proxy->id.name);
+ continue;
+ }
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ /* We can only switch the proxy'ing to a made-local proxy if it is no longer
+ * referred to from a library. Not checking for local use; if new local proxy
+ * was not used locally would be a nasty bug! */
+ if (is_local || is_lib) {
+ printf("Warning, made-local proxy object %s will loose its link to %s, "
+ "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n",
+ id->newid->name, ob->proxy->id.name, is_local, is_lib);
+ }
+ else {
+ /* we can switch the proxy'ing from the linked-in to the made-local proxy.
+ * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
+ * was already allocated by BKE_object_make_local_ex() (which called BKE_object_copy_ex). */
+ ob_new->proxy = ob->proxy;
+ ob_new->proxy_group = ob->proxy_group;
+ ob_new->proxy_from = ob->proxy_from;
+ ob_new->proxy->proxy_from = ob_new;
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
+ }
+ }
+ }
+
+#ifdef DEBUG_TIME
+ printf("Step 5: Proxy 'remapping' hack: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+#else
+ LinkNode *linked_loop_candidates = NULL;
+
/* Step 5: remove datablocks that have been copied to be localized and are no more used in the end...
* Note that we may have to loop more than once here, to tackle dependencies between linked objects... */
bool do_loop = true;
@@ -1803,6 +2210,8 @@ void BKE_library_make_local(
if (!is_local) {
if (!is_lib) { /* Not used at all, we can free it! */
+ BLI_assert(!"Unused linked data copy remaining from MakeLibLocal process, should not happen anymore");
+ printf("\t%s (from %s)\n", id->name, id->lib->id.name);
BKE_libblock_free(bmain, id);
it->link = NULL;
do_loop = true;
@@ -1816,7 +2225,7 @@ void BKE_library_make_local(
/* Grrrrrrr... those half-datablocks-stuff... grrrrrrrrrrr...
* Here we have to also tag them as potential candidates, otherwise they would falsy report
- * ID they used as 'directly used' in fourth step. */
+ * ID they used as 'directly used' in sixth step. */
ID *ntree = (ID *)ntreeFromID(id);
if (ntree != NULL) {
ntree->tag |= LIB_TAG_DOIT;
@@ -1826,6 +2235,11 @@ void BKE_library_make_local(
}
}
+#ifdef DEBUG_TIME
+ printf("Step 5: Remove linked datablocks that have been copied and ended fully localized: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
/* Step 6: Try to find circle dependencies between indirectly-linked-only datablocks.
* Those are fake 'usages' that prevent their deletion. See T49775 for nice ugly case. */
BKE_library_unused_linked_data_set_tag(bmain, false);
@@ -1841,6 +2255,7 @@ void BKE_library_make_local(
/* Note: in theory here we are only handling datablocks forming exclusive linked dependency-cycles-based
* archipelagos, so no need to check again after we have deleted one, as done in previous step. */
if (id->tag & LIB_TAG_DOIT) {
+ BLI_assert(!"Unused linked data copy remaining from MakeLibLocal process (archipelago case), should not happen anymore");
/* Object's deletion rely on valid ob->data, but ob->data may have already been freed here...
* Setting it to NULL may not be 100% correct, but should be safe and do the work. */
if (GS(id->name) == ID_OB) {
@@ -1862,7 +2277,37 @@ void BKE_library_make_local(
}
}
+#ifdef DEBUG_TIME
+ printf("Step 6: Try to find circle dependencies between indirectly-linked-only datablocks: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+#endif
+
+ /* This is probably more of a hack than something we should do here, but...
+ * Issue is, the whole copying + remapping done in complex cases above may leave pose channels of armatures
+ * in complete invalid state (more precisely, the bone pointers of the pchans - very crappy cross-datablocks
+ * relationship), se we tag it to be fully recomputed, but this does not seems to be enough in some cases,
+ * and evaluation code ends up trying to evaluate a not-yet-updated armature object's deformations.
+ * Try "make all local" in 04_01_H.lighting.blend from Agent327 without this, e.g. */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->data != NULL && ob->type == OB_ARMATURE && ob->pose != NULL && ob->pose->flag & POSE_RECALC) {
+ BKE_pose_rebuild(ob, ob->data);
+ }
+ }
+
+#ifdef DEBUG_TIME
+ printf("Hack: Forcefully rebuild armature object poses: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+ BKE_main_id_clear_newpoins(bmain);
BLI_memarena_free(linklist_mem);
+
+#ifdef DEBUG_TIME
+ printf("Cleanup and finish: Done.\n");
+ TIMEIT_END(make_local);
+#endif
}
/**
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index fa75c906fb1..d1f0c87183d 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -33,6 +33,7 @@
#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
@@ -70,10 +71,12 @@
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_fcurve.h"
+#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
+#include "BKE_node.h"
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
#include "BKE_sca.h"
@@ -82,13 +85,16 @@
#define FOREACH_FINALIZE _finalize
-#define FOREACH_FINALIZE_VOID FOREACH_FINALIZE: (void)0
+#define FOREACH_FINALIZE_VOID \
+ if (0) { goto FOREACH_FINALIZE; } \
+ FOREACH_FINALIZE: ((void)0)
-#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, cb_flag) \
+#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, _cb_flag) \
+ CHECK_TYPE(id_pp, ID **); \
if (!((_data)->status & IDWALK_STOP)) { \
const int _flag = (_data)->flag; \
ID *old_id = *(id_pp); \
- const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag | (_data)->cd_flag); \
+ const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, _cb_flag | (_data)->cb_flag); \
if (_flag & IDWALK_READONLY) { \
BLI_assert(*(id_pp) == old_id); \
} \
@@ -129,7 +135,7 @@ enum {
typedef struct LibraryForeachIDData {
ID *self_id;
int flag;
- int cd_flag;
+ int cb_flag;
LibraryIDLinkCallback callback;
void *user_data;
int status;
@@ -139,20 +145,51 @@ typedef struct LibraryForeachIDData {
BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
+static void library_foreach_idproperty_ID_link(LibraryForeachIDData *data, IDProperty *prop, int flag)
+{
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_GROUP:
+ {
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ library_foreach_idproperty_ID_link(data, loop, flag);
+ }
+ break;
+ }
+ case IDP_IDPARRAY:
+ {
+ IDProperty *loop = IDP_Array(prop);
+ for (int i = 0; i < prop->len; i++) {
+ library_foreach_idproperty_ID_link(data, &loop[i], flag);
+ }
+ break;
+ }
+ case IDP_ID:
+ FOREACH_CALLBACK_INVOKE_ID(data, prop->data.pointer, flag);
+ break;
+ default:
+ break; /* Nothing to do here with other types of IDProperties... */
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_rigidbodyworldSceneLooper(
- struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cd_flag)
+ struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_modifiersForeachIDLink(
- void *user_data, Object *UNUSED(object), ID **id_pointer, int cd_flag)
+ void *user_data, Object *UNUSED(object), ID **id_pointer, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
@@ -161,44 +198,44 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID
bool is_reference, void *user_data)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- const int cd_flag = is_reference ? IDWALK_USER : IDWALK_NOP;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_particlesystemsObjectLooper(
- ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cd_flag)
+ ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_sensorsObjectLooper(
- bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cd_flag)
+ bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_controllersObjectLooper(
- bController *UNUSED(controller), ID **id_pointer, void *user_data, int cd_flag)
+ bController *UNUSED(controller), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_actuatorsObjectLooper(
- bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cd_flag)
+ bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
@@ -207,7 +244,7 @@ static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *stri
{
NlaStrip *substrip;
- FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_CB_USER);
for (substrip = strip->strips.first; substrip; substrip = substrip->next) {
library_foreach_nla_strip(data, substrip);
@@ -230,14 +267,14 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
/* only used targets */
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_NOP);
+ FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP);
}
DRIVER_TARGETS_LOOPER_END
}
}
- FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_USER);
- FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_CB_USER);
+ FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_CB_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) {
@@ -250,23 +287,39 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
{
- FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_NOP);
- FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_CB_NOP);
+ FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_CB_USER);
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_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER);
+ FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER);
+
+ FOREACH_FINALIZE_VOID;
+}
+
+static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone)
+{
+ library_foreach_idproperty_ID_link(data, bone->prop, IDWALK_CB_USER);
+
+ for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) {
+ library_foreach_bone(data, curbone);
+ }
FOREACH_FINALIZE_VOID;
}
static void library_foreach_ID_as_subdata_link(
- ID *id, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data)
+ ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data)
{
+ /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */
+ ID *id = *id_pp;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_PRIVATE);
+ BLI_assert(id == *id_pp);
+
if (flag & IDWALK_RECURSE) {
/* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in IDWALK_RECURSE case is
* troublesome, see T49553. */
@@ -276,8 +329,10 @@ static void library_foreach_ID_as_subdata_link(
}
}
else {
- BKE_library_foreach_ID_link(id, callback, user_data, flag);
+ BKE_library_foreach_ID_link(NULL, id, callback, user_data, flag);
}
+
+ FOREACH_FINALIZE_VOID;
}
/**
@@ -285,7 +340,7 @@ static void library_foreach_ID_as_subdata_link(
*
* \note: May be extended to be recursive in the future.
*/
-void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
+void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
{
LibraryForeachIDData data;
int i;
@@ -313,9 +368,23 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag)
- do {
+ for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
data.self_id = id;
- data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0;
+ data.cb_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_CB_INDIRECT_USAGE : 0;
+
+ if (bmain != NULL && bmain->relations != NULL && (flag & IDWALK_READONLY)) {
+ /* Note that this is minor optimization, even in worst cases (like id being an object with lots of
+ * drivers and constraints and modifiers, or material etc. with huge node tree),
+ * but we might as well use it (Main->relations is always assumed valid, it's responsability of code
+ * creating it to free it, especially if/when it starts modifying Main database). */
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
+ for (; entry != NULL; entry = entry->next) {
+ FOREACH_CALLBACK_INVOKE_ID_PP(&data, entry->id_pointer, entry->usage_flag);
+ }
+ continue;
+ }
+
+ library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER);
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
@@ -326,7 +395,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_LI:
{
Library *lib = (Library *) id;
- CALLBACK_INVOKE(lib->parent, IDWALK_NOP);
+ CALLBACK_INVOKE(lib->parent, IDWALK_CB_NOP);
break;
}
case ID_SCE:
@@ -336,39 +405,39 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
SceneRenderLayer *srl;
Base *base;
- CALLBACK_INVOKE(scene->camera, IDWALK_NOP);
- CALLBACK_INVOKE(scene->world, IDWALK_USER);
- CALLBACK_INVOKE(scene->set, IDWALK_NOP);
- CALLBACK_INVOKE(scene->clip, IDWALK_USER);
+ CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(scene->world, IDWALK_CB_USER);
+ CALLBACK_INVOKE(scene->set, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(scene->clip, IDWALK_CB_USER);
if (scene->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID *)scene->nodetree, callback, user_data, flag, &data);
+ library_foreach_ID_as_subdata_link((ID **)&scene->nodetree, callback, user_data, flag, &data);
}
/* 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);
+ CALLBACK_INVOKE(scene->obedit, IDWALK_CB_NOP);
for (srl = scene->r.layers.first; srl; srl = srl->next) {
FreestyleModuleConfig *fmc;
FreestyleLineSet *fls;
if (srl->mat_override) {
- CALLBACK_INVOKE(srl->mat_override, IDWALK_USER);
+ CALLBACK_INVOKE(srl->mat_override, IDWALK_CB_USER);
}
if (srl->light_override) {
- CALLBACK_INVOKE(srl->light_override, IDWALK_USER);
+ CALLBACK_INVOKE(srl->light_override, IDWALK_CB_USER);
}
for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
if (fmc->script) {
- CALLBACK_INVOKE(fmc->script, IDWALK_NOP);
+ CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
}
}
for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
if (fls->group) {
- CALLBACK_INVOKE(fls->group, IDWALK_USER);
+ CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
}
if (fls->linestyle) {
- CALLBACK_INVOKE(fls->linestyle, IDWALK_USER);
+ CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
}
}
}
@@ -377,39 +446,40 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
Sequence *seq;
SEQP_BEGIN(scene->ed, seq)
{
- CALLBACK_INVOKE(seq->scene, IDWALK_NOP);
- CALLBACK_INVOKE(seq->scene_camera, IDWALK_NOP);
- CALLBACK_INVOKE(seq->clip, IDWALK_USER);
- CALLBACK_INVOKE(seq->mask, IDWALK_USER);
- CALLBACK_INVOKE(seq->sound, IDWALK_USER);
+ CALLBACK_INVOKE(seq->scene, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(seq->scene_camera, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER);
+ CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER);
+ CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER);
+ library_foreach_idproperty_ID_link(&data, seq->prop, IDWALK_CB_USER);
for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) {
- CALLBACK_INVOKE(smd->mask_id, IDWALK_USER);
+ CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER);
}
}
SEQ_END
}
- CALLBACK_INVOKE(scene->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
for (base = scene->base.first; base; base = base->next) {
- CALLBACK_INVOKE(base->object, IDWALK_USER);
+ CALLBACK_INVOKE(base->object, IDWALK_CB_USER);
}
for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
- CALLBACK_INVOKE(marker->camera, IDWALK_NOP);
+ CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
}
if (toolsett) {
- CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_CB_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->particle.scene, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_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);
+ CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_CB_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_CB_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_CB_USER);
if (toolsett->vpaint) {
library_foreach_paint(&data, &toolsett->vpaint->paint);
@@ -419,7 +489,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (toolsett->sculpt) {
library_foreach_paint(&data, &toolsett->sculpt->paint);
- CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_CB_NOP);
}
if (toolsett->uvsculpt) {
library_foreach_paint(&data, &toolsett->uvsculpt->paint);
@@ -430,7 +500,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data);
}
- CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_NOP);
+ CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_CB_NOP);
break;
}
@@ -441,75 +511,77 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
ParticleSystem *psys;
/* Object is special, proxies make things hard... */
- const int data_cd_flag = data.cd_flag;
- const int proxy_cd_flag = (object->proxy || object->proxy_group) ? IDWALK_INDIRECT_USAGE : 0;
+ const int data_cb_flag = data.cb_flag;
+ const int proxy_cb_flag = ((data.flag & IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 && (object->proxy || object->proxy_group)) ?
+ IDWALK_CB_INDIRECT_USAGE : 0;
/* object data special case */
- data.cd_flag |= proxy_cd_flag;
+ data.cb_flag |= proxy_cb_flag;
if (object->type == OB_EMPTY) {
/* empty can have NULL or Image */
- CALLBACK_INVOKE_ID(object->data, IDWALK_USER);
+ CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER);
}
else {
/* when set, this can't be NULL */
if (object->data) {
- CALLBACK_INVOKE_ID(object->data, IDWALK_USER | IDWALK_NEVER_NULL);
+ CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
}
}
- data.cd_flag = data_cd_flag;
+ data.cb_flag = data_cb_flag;
- CALLBACK_INVOKE(object->parent, IDWALK_NOP);
- CALLBACK_INVOKE(object->track, IDWALK_NOP);
+ CALLBACK_INVOKE(object->parent, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(object->track, IDWALK_CB_NOP);
/* object->proxy is refcounted, but not object->proxy_group... *sigh* */
- CALLBACK_INVOKE(object->proxy, IDWALK_USER);
- CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP);
+ CALLBACK_INVOKE(object->proxy, IDWALK_CB_USER);
+ CALLBACK_INVOKE(object->proxy_group, IDWALK_CB_NOP);
/* Special case!
* Since this field is set/owned by 'user' of this ID (and not ID itself), it is only indirect usage
* if proxy object is linked... Twisted. */
if (object->proxy_from) {
- data.cd_flag = ID_IS_LINKED_DATABLOCK(object->proxy_from) ? IDWALK_INDIRECT_USAGE : 0;
+ data.cb_flag = ID_IS_LINKED_DATABLOCK(object->proxy_from) ? IDWALK_CB_INDIRECT_USAGE : 0;
}
- CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
- data.cd_flag = data_cd_flag;
+ CALLBACK_INVOKE(object->proxy_from, IDWALK_CB_LOOPBACK);
+ data.cb_flag = data_cb_flag;
- CALLBACK_INVOKE(object->poselib, IDWALK_USER);
+ CALLBACK_INVOKE(object->poselib, IDWALK_CB_USER);
- data.cd_flag |= proxy_cd_flag;
+ data.cb_flag |= proxy_cb_flag;
for (i = 0; i < object->totcol; i++) {
- CALLBACK_INVOKE(object->mat[i], IDWALK_USER);
+ CALLBACK_INVOKE(object->mat[i], IDWALK_CB_USER);
}
- data.cd_flag = data_cd_flag;
+ data.cb_flag = data_cb_flag;
- CALLBACK_INVOKE(object->gpd, IDWALK_USER);
- CALLBACK_INVOKE(object->dup_group, IDWALK_USER);
+ CALLBACK_INVOKE(object->gpd, IDWALK_CB_USER);
+ CALLBACK_INVOKE(object->dup_group, IDWALK_CB_USER);
if (object->pd) {
- CALLBACK_INVOKE(object->pd->tex, IDWALK_USER);
- CALLBACK_INVOKE(object->pd->f_source, IDWALK_NOP);
+ CALLBACK_INVOKE(object->pd->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(object->pd->f_source, IDWALK_CB_NOP);
}
/* Note that ob->effect is deprecated, so no need to handle it here. */
if (object->pose) {
bPoseChannel *pchan;
- data.cd_flag |= proxy_cd_flag;
+ data.cb_flag |= proxy_cb_flag;
for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
- CALLBACK_INVOKE(pchan->custom, IDWALK_USER);
+ library_foreach_idproperty_ID_link(&data, pchan->prop, IDWALK_CB_USER);
+ CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER);
BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data);
}
- data.cd_flag = data_cd_flag;
+ data.cb_flag = data_cb_flag;
}
if (object->rigidbody_constraint) {
- CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_NOP);
- CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_NOP);
+ CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_CB_NOP);
}
if (object->lodlevels.first) {
LodLevel *level;
for (level = object->lodlevels.first; level; level = level->next) {
- CALLBACK_INVOKE(level->source, IDWALK_NOP);
+ CALLBACK_INVOKE(level->source, IDWALK_CB_NOP);
}
}
@@ -521,10 +593,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (object->soft) {
- CALLBACK_INVOKE(object->soft->collision_group, IDWALK_NOP);
+ CALLBACK_INVOKE(object->soft->collision_group, IDWALK_CB_NOP);
if (object->soft->effector_weights) {
- CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP);
+ CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP);
}
}
@@ -534,13 +606,23 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
break;
}
+ case ID_AR:
+ {
+ bArmature *arm = (bArmature *)id;
+
+ for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
+ library_foreach_bone(&data, bone);
+ }
+ break;
+ }
+
case ID_ME:
{
Mesh *mesh = (Mesh *) id;
- CALLBACK_INVOKE(mesh->texcomesh, IDWALK_USER);
- CALLBACK_INVOKE(mesh->key, IDWALK_USER);
+ CALLBACK_INVOKE(mesh->texcomesh, IDWALK_CB_USER);
+ CALLBACK_INVOKE(mesh->key, IDWALK_CB_USER);
for (i = 0; i < mesh->totcol; i++) {
- CALLBACK_INVOKE(mesh->mat[i], IDWALK_USER);
+ CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER);
}
/* XXX Really not happy with this - probably texface should rather use some kind of
@@ -552,7 +634,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data;
for (int j = 0; j < mesh->totpoly; j++, txface++) {
- CALLBACK_INVOKE(txface->tpage, IDWALK_USER_ONE);
+ CALLBACK_INVOKE(txface->tpage, IDWALK_CB_USER_ONE);
}
}
}
@@ -562,7 +644,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
MTFace *tface = (MTFace *)mesh->fdata.layers[i].data;
for (int j = 0; j < mesh->totface; j++, tface++) {
- CALLBACK_INVOKE(tface->tpage, IDWALK_USER_ONE);
+ CALLBACK_INVOKE(tface->tpage, IDWALK_CB_USER_ONE);
}
}
}
@@ -573,17 +655,17 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_CU:
{
Curve *curve = (Curve *) id;
- CALLBACK_INVOKE(curve->bevobj, IDWALK_NOP);
- CALLBACK_INVOKE(curve->taperobj, IDWALK_NOP);
- CALLBACK_INVOKE(curve->textoncurve, IDWALK_NOP);
- CALLBACK_INVOKE(curve->key, IDWALK_USER);
+ CALLBACK_INVOKE(curve->bevobj, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->taperobj, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->textoncurve, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->key, IDWALK_CB_USER);
for (i = 0; i < curve->totcol; i++) {
- CALLBACK_INVOKE(curve->mat[i], IDWALK_USER);
+ CALLBACK_INVOKE(curve->mat[i], IDWALK_CB_USER);
}
- CALLBACK_INVOKE(curve->vfont, IDWALK_USER);
- CALLBACK_INVOKE(curve->vfontb, IDWALK_USER);
- CALLBACK_INVOKE(curve->vfonti, IDWALK_USER);
- CALLBACK_INVOKE(curve->vfontbi, IDWALK_USER);
+ CALLBACK_INVOKE(curve->vfont, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfontb, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfonti, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfontbi, IDWALK_CB_USER);
break;
}
@@ -591,7 +673,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
{
MetaBall *metaball = (MetaBall *) id;
for (i = 0; i < metaball->totcol; i++) {
- CALLBACK_INVOKE(metaball->mat[i], IDWALK_USER);
+ CALLBACK_INVOKE(metaball->mat[i], IDWALK_CB_USER);
}
break;
}
@@ -606,9 +688,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (material->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID *)material->nodetree, callback, user_data, flag, &data);
+ library_foreach_ID_as_subdata_link((ID **)&material->nodetree, callback, user_data, flag, &data);
}
- CALLBACK_INVOKE(material->group, IDWALK_USER);
+ CALLBACK_INVOKE(material->group, IDWALK_CB_USER);
break;
}
@@ -617,26 +699,26 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
Tex *texture = (Tex *) id;
if (texture->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID *)texture->nodetree, callback, user_data, flag, &data);
+ library_foreach_ID_as_subdata_link((ID **)&texture->nodetree, callback, user_data, flag, &data);
}
- CALLBACK_INVOKE(texture->ima, IDWALK_USER);
+ CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER);
if (texture->env) {
- CALLBACK_INVOKE(texture->env->object, IDWALK_NOP);
- CALLBACK_INVOKE(texture->env->ima, IDWALK_USER);
+ CALLBACK_INVOKE(texture->env->object, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(texture->env->ima, IDWALK_CB_USER);
}
if (texture->pd)
- CALLBACK_INVOKE(texture->pd->object, IDWALK_NOP);
+ CALLBACK_INVOKE(texture->pd->object, IDWALK_CB_NOP);
if (texture->vd)
- CALLBACK_INVOKE(texture->vd->object, IDWALK_NOP);
+ CALLBACK_INVOKE(texture->vd->object, IDWALK_CB_NOP);
if (texture->ot)
- CALLBACK_INVOKE(texture->ot->object, IDWALK_NOP);
+ CALLBACK_INVOKE(texture->ot->object, IDWALK_CB_NOP);
break;
}
case ID_LT:
{
Lattice *lattice = (Lattice *) id;
- CALLBACK_INVOKE(lattice->key, IDWALK_USER);
+ CALLBACK_INVOKE(lattice->key, IDWALK_CB_USER);
break;
}
@@ -650,7 +732,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (lamp->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID *)lamp->nodetree, callback, user_data, flag, &data);
+ library_foreach_ID_as_subdata_link((ID **)&lamp->nodetree, callback, user_data, flag, &data);
}
break;
}
@@ -658,25 +740,21 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_CA:
{
Camera *camera = (Camera *) id;
- CALLBACK_INVOKE(camera->dof_ob, IDWALK_NOP);
+ CALLBACK_INVOKE(camera->dof_ob, IDWALK_CB_NOP);
break;
}
case ID_KE:
{
- /* XXX Only ID pointer from shapekeys is the 'from' one, which is not actually ID usage.
- * Maybe we should even nuke it from here, not 100% sure yet...
- * (see also foreach_libblock_id_users_callback).
- */
Key *key = (Key *) id;
- CALLBACK_INVOKE_ID(key->from, IDWALK_NOP);
+ CALLBACK_INVOKE_ID(key->from, IDWALK_CB_LOOPBACK);
break;
}
case ID_SCR:
{
bScreen *screen = (bScreen *) id;
- CALLBACK_INVOKE(screen->scene, IDWALK_USER_ONE);
+ CALLBACK_INVOKE(screen->scene, IDWALK_CB_USER_ONE);
break;
}
@@ -690,7 +768,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (world->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID *)world->nodetree, callback, user_data, flag, &data);
+ library_foreach_ID_as_subdata_link((ID **)&world->nodetree, callback, user_data, flag, &data);
}
break;
}
@@ -698,7 +776,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_SPK:
{
Speaker *speaker = (Speaker *) id;
- CALLBACK_INVOKE(speaker->sound, IDWALK_USER);
+ CALLBACK_INVOKE(speaker->sound, IDWALK_CB_USER);
break;
}
@@ -707,7 +785,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
Group *group = (Group *) id;
GroupObject *gob;
for (gob = group->gobject.first; gob; gob = gob->next) {
- CALLBACK_INVOKE(gob->ob, IDWALK_USER_ONE);
+ CALLBACK_INVOKE(gob->ob, IDWALK_CB_USER_ONE);
}
break;
}
@@ -716,9 +794,27 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
{
bNodeTree *ntree = (bNodeTree *) id;
bNode *node;
- CALLBACK_INVOKE(ntree->gpd, IDWALK_USER);
+ bNodeSocket *sock;
+
+ CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER);
+
for (node = ntree->nodes.first; node; node = node->next) {
- CALLBACK_INVOKE_ID(node->id, IDWALK_USER);
+ CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER);
+
+ library_foreach_idproperty_ID_link(&data, node->prop, IDWALK_CB_USER);
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ }
+
+ for (sock = ntree->inputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ for (sock = ntree->outputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
}
break;
}
@@ -726,9 +822,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_BR:
{
Brush *brush = (Brush *) id;
- CALLBACK_INVOKE(brush->toggle_brush, IDWALK_NOP);
- CALLBACK_INVOKE(brush->clone.image, IDWALK_NOP);
- CALLBACK_INVOKE(brush->paint_curve, IDWALK_USER);
+ CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
library_foreach_mtex(&data, &brush->mtex);
library_foreach_mtex(&data, &brush->mask_mtex);
break;
@@ -737,10 +833,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_PA:
{
ParticleSettings *psett = (ParticleSettings *) id;
- CALLBACK_INVOKE(psett->dup_group, IDWALK_NOP);
- CALLBACK_INVOKE(psett->dup_ob, IDWALK_NOP);
- CALLBACK_INVOKE(psett->bb_ob, IDWALK_NOP);
- CALLBACK_INVOKE(psett->collision_group, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->dup_group, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(psett->dup_ob, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(psett->bb_ob, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(psett->collision_group, IDWALK_CB_NOP);
for (i = 0; i < MAX_MTEX; i++) {
if (psett->mtex[i]) {
@@ -749,16 +845,16 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (psett->effector_weights) {
- CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_CB_NOP);
}
if (psett->pd) {
- CALLBACK_INVOKE(psett->pd->tex, IDWALK_USER);
- CALLBACK_INVOKE(psett->pd->f_source, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->pd->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(psett->pd->f_source, IDWALK_CB_NOP);
}
if (psett->pd2) {
- CALLBACK_INVOKE(psett->pd2->tex, IDWALK_USER);
- CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->pd2->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_CB_NOP);
}
if (psett->boids) {
@@ -769,11 +865,11 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
for (rule = state->rules.first; rule; rule = rule->next) {
if (rule->type == eBoidRuleType_Avoid) {
BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
- CALLBACK_INVOKE(gabr->ob, IDWALK_NOP);
+ CALLBACK_INVOKE(gabr->ob, IDWALK_CB_NOP);
}
else if (rule->type == eBoidRuleType_FollowLeader) {
BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
- CALLBACK_INVOKE(flbr->ob, IDWALK_NOP);
+ CALLBACK_INVOKE(flbr->ob, IDWALK_CB_NOP);
}
}
}
@@ -789,19 +885,19 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
MovieTrackingTrack *track;
MovieTrackingPlaneTrack *plane_track;
- CALLBACK_INVOKE(clip->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(clip->gpd, IDWALK_CB_USER);
for (track = tracking->tracks.first; track; track = track->next) {
- CALLBACK_INVOKE(track->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(track->gpd, IDWALK_CB_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);
+ CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
}
}
for (plane_track = tracking->plane_tracks.first; plane_track; plane_track = plane_track->next) {
- CALLBACK_INVOKE(plane_track->image, IDWALK_USER);
+ CALLBACK_INVOKE(plane_track->image, IDWALK_CB_USER);
}
break;
}
@@ -816,7 +912,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
for (mask_spline = mask_layer->splines.first; mask_spline; mask_spline = mask_spline->next) {
for (i = 0; i < mask_spline->tot_point; i++) {
MaskSplinePoint *point = &mask_spline->points[i];
- CALLBACK_INVOKE_ID(point->parent.id, IDWALK_USER);
+ CALLBACK_INVOKE_ID(point->parent.id, IDWALK_CB_USER);
}
}
}
@@ -834,14 +930,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (linestyle->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID *)linestyle->nodetree, callback, user_data, flag, &data);
+ library_foreach_ID_as_subdata_link((ID **)&linestyle->nodetree, callback, user_data, flag, &data);
}
for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) {
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)lsm;
if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
}
}
}
@@ -849,7 +945,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)lsm;
if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
}
}
}
@@ -857,7 +953,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)lsm;
if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
}
}
}
@@ -868,7 +964,16 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
bAction *act = (bAction *) id;
for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
- CALLBACK_INVOKE(marker->camera, IDWALK_NOP);
+ CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
+ }
+ break;
+ }
+ case ID_GD:
+ {
+ bGPdata *gpencil = (bGPdata *) id;
+
+ for (bGPDlayer *gp_layer = gpencil->layers.first; gp_layer; gp_layer = gp_layer->next) {
+ CALLBACK_INVOKE(gp_layer->parent, IDWALK_CB_NOP);
}
break;
}
@@ -878,8 +983,6 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_VF:
case ID_TXT:
case ID_SO:
- case ID_AR:
- case ID_GD:
case ID_WM:
case ID_PAL:
case ID_PC:
@@ -891,7 +994,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
break;
}
- } while ((id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL));
+ }
FOREACH_FINALIZE:
if (data.ids_handled) {
@@ -909,13 +1012,13 @@ FOREACH_FINALIZE:
/**
* re-usable function, use when replacing ID's
*/
-void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag)
+void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
{
- if (cd_flag & IDWALK_USER) {
+ if (cb_flag & IDWALK_CB_USER) {
id_us_min(id_src);
id_us_plus(id_dst);
}
- else if (cd_flag & IDWALK_USER_ONE) {
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
id_us_ensure_real(id_dst);
}
}
@@ -928,9 +1031,25 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag)
*/
/* XXX This has to be fully rethink, basing check on ID type is not really working anymore (and even worth once
* IDProps will support ID pointers), we'll have to do some quick checks on IDs themselves... */
-bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used)
+bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
{
- if (id_type_can_have_animdata(id_type_owner)) {
+ /* any type of ID can be used in custom props. */
+ if (id_owner->properties) {
+ return true;
+ }
+
+ const short id_type_owner = GS(id_owner->name);
+
+ /* IDProps of armature bones and nodes, and bNode->id can use virtually any type of ID. */
+ if (ELEM(id_type_owner, ID_NT, ID_AR)) {
+ return true;
+ }
+
+ if (ntreeFromID(id_owner)) {
+ return true;
+ }
+
+ if (BKE_animdata_from_id(id_owner)) {
return true; /* AnimationData can use virtually any kind of datablocks, through drivers especially. */
}
@@ -939,8 +1058,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
return ELEM(id_type_used, ID_LI);
case ID_SCE:
return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT,
- ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT) ||
- BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT));
case ID_OB:
/* Could be the following, but simpler to just always say 'yes' here. */
#if 0
@@ -957,13 +1075,13 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
case ID_MB:
return ELEM(id_type_used, ID_MA);
case ID_MA:
- return (ELEM(id_type_used, ID_TE, ID_GR) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE, ID_GR));
case ID_TE:
- return (ELEM(id_type_used, ID_IM, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_IM, ID_OB));
case ID_LT:
return ELEM(id_type_used, ID_KE);
case ID_LA:
- return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE));
case ID_CA:
return ELEM(id_type_used, ID_OB);
case ID_KE:
@@ -971,7 +1089,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
case ID_SCR:
return ELEM(id_type_used, ID_SCE);
case ID_WO:
- return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE));
case ID_SPK:
return ELEM(id_type_used, ID_SO);
case ID_GR:
@@ -992,7 +1110,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
case ID_MSK:
return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
case ID_LS:
- return (ELEM(id_type_used, ID_TE, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE, ID_OB));
case ID_IM:
case ID_VF:
case ID_TXT:
@@ -1025,20 +1143,15 @@ typedef struct IDUsersIter {
int count_direct, count_indirect; /* Set by callback. */
} IDUsersIter;
-static int foreach_libblock_id_users_callback(void *user_data, ID *self_id, ID **id_p, int 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) {
- /* XXX This is actually some kind of hack...
- * Issue is, shapekeys' 'from' ID pointer is not actually ID usage.
- * Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
+ /* 'Loopback' ID pointers (the ugly 'from' ones, Object->proxy_from and Key->from).
+ * Those are not actually ID usage, we can ignore them here.
*/
- if ((GS(self_id->name) == ID_KE) && (((Key *)self_id)->from == *id_p)) {
- return IDWALK_RET_NOP;
- }
- /* XXX another hack, for similar reasons as above one. */
- if ((GS(self_id->name) == ID_OB) && (((Object *)self_id)->proxy_from == (Object *)*id_p)) {
+ if (cb_flag & IDWALK_CB_LOOPBACK) {
return IDWALK_RET_NOP;
}
@@ -1049,7 +1162,7 @@ static int foreach_libblock_id_users_callback(void *user_data, ID *self_id, ID *
(iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
(cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
#endif
- if (cb_flag & IDWALK_INDIRECT_USAGE) {
+ if (cb_flag & IDWALK_CB_INDIRECT_USAGE) {
iter->count_indirect++;
}
else {
@@ -1080,7 +1193,7 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
iter.curr_id = id_user;
iter.count_direct = iter.count_indirect = 0;
- BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP);
+ BKE_library_foreach_ID_link(NULL, iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_READONLY);
return iter.count_direct + iter.count_indirect;
}
@@ -1098,7 +1211,7 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
while (i-- && !is_defined) {
ID *id_curr = lb_array[i]->first;
- if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+ if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
continue;
}
@@ -1109,7 +1222,7 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
}
iter.curr_id = id_curr;
BKE_library_foreach_ID_link(
- id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+ bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0);
}
@@ -1150,7 +1263,7 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
while (i-- && !is_defined) {
ID *id_curr = lb_array[i]->first;
- if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+ if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
continue;
}
@@ -1160,7 +1273,7 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
continue;
}
iter.curr_id = id_curr;
- BKE_library_foreach_ID_link(id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+ BKE_library_foreach_ID_link(bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
is_defined = (iter.count_direct != 0 && iter.count_indirect != 0);
}
@@ -1237,7 +1350,8 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
/* Unused ID (so far), no need to check it further. */
continue;
}
- BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
+ BKE_library_foreach_ID_link(
+ bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
}
}
}
@@ -1264,7 +1378,8 @@ void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
/* Local or non-indirectly-used ID (so far), no need to check it further. */
continue;
}
- BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
+ BKE_library_foreach_ID_link(
+ bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
}
}
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 62f59832481..f8c193fe108 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -158,6 +158,10 @@ enum {
static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id_p, int cb_flag)
{
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
IDRemap *id_remap_data = user_data;
ID *old_id = id_remap_data->old_id;
ID *new_id = id_remap_data->new_id;
@@ -169,23 +173,24 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
}
if (*id_p && (*id_p == old_id)) {
- const bool is_indirect = (cb_flag & IDWALK_INDIRECT_USAGE) != 0;
+ const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
/* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
* on the other hand since they get reset to lib data on file open/reload it is indirect too...
* Edit Mode is also a 'skip direct' case. */
const bool is_obj = (GS(id->name) == ID_OB);
+ const bool is_obj_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) &&
+ const bool is_never_null = ((cb_flag & IDWALK_CB_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);
+ printf("In %s: Remapping %s (%p) to %s (%p) (is_indirect: %d, skip_indirect: %d)\n",
+ id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, is_indirect, skip_indirect);
#endif
- if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) {
+ if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) {
id->tag |= LIB_TAG_DOIT;
}
@@ -196,6 +201,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
{
if (is_indirect) {
id_remap_data->skipped_indirect++;
+ if (is_obj) {
+ Object *ob = (Object *)id;
+ if (ob->data == *id_p && ob->proxy != NULL) {
+ /* And another 'Proudly brought to you by Proxy Hell' hack!
+ * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */
+ id_remap_data->skipped_direct++;
+ }
+ }
}
else if (is_never_null || is_obj_editmode) {
id_remap_data->skipped_direct++;
@@ -203,10 +216,10 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
else {
BLI_assert(0);
}
- if (cb_flag & IDWALK_USER) {
+ if (cb_flag & IDWALK_CB_USER) {
id_remap_data->skipped_refcounted++;
}
- else if (cb_flag & IDWALK_USER_ONE) {
+ else if (cb_flag & IDWALK_CB_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;
}
@@ -216,18 +229,18 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
*id_p = new_id;
DAG_id_tag_update_ex(id_remap_data->bmain, id_self, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
- if (cb_flag & IDWALK_USER) {
+ if (cb_flag & IDWALK_CB_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) {
+ else if (cb_flag & IDWALK_CB_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) {
+ if (!is_indirect || is_obj_proxy) {
id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
}
}
@@ -236,7 +249,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
return IDWALK_RET_NOP;
}
-/* Some reamapping unfortunately require extra and/or specific handling, tackle those here. */
+/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */
static void libblock_remap_data_preprocess_scene_base_unlink(
IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect)
{
@@ -313,7 +326,7 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
}
}
-static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, Object *old_ob, Object *new_ob)
+static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *old_ob, Object *new_ob)
{
if (old_ob->flag & OB_FROMGROUP) {
/* Note that for Scene's BaseObject->flag, either we:
@@ -332,6 +345,13 @@ static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain,
new_ob->flag |= OB_FROMGROUP;
}
}
+ if (old_ob->type == OB_MBALL) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->type == OB_MBALL && BKE_mball_is_basis_for(ob, old_ob)) {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ }
+ }
}
static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmain), Scene *sce, ID *old_id)
@@ -414,6 +434,7 @@ ATTR_NONNULL(1) static void libblock_remap_data(
IDRemap id_remap_data;
ListBase *lb_array[MAX_LIBARRAY];
int i;
+ const int foreach_id_flags = (remap_flags & ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE) != 0 ? IDWALK_NO_INDIRECT_PROXY_DATA_USAGE : IDWALK_NOP;
if (r_id_remap_data == NULL) {
r_id_remap_data = &id_remap_data;
@@ -434,7 +455,7 @@ ATTR_NONNULL(1) static void libblock_remap_data(
#endif
r_id_remap_data->id = id;
libblock_remap_data_preprocess(r_id_remap_data);
- BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ BKE_library_foreach_ID_link(NULL, id, foreach_libblock_remap_callback, (void *)r_id_remap_data, foreach_id_flags);
}
else {
i = set_listbasepointers(bmain, lb_array);
@@ -443,20 +464,16 @@ ATTR_NONNULL(1) static void libblock_remap_data(
* 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;
-
- if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(old_id->name))) {
- continue;
- }
-
- for (; id_curr; id_curr = id_curr->next) {
- /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
- * the user count handling...
- * XXX No more true (except for debug usage of those skipping counters). */
- r_id_remap_data->id = id_curr;
- libblock_remap_data_preprocess(r_id_remap_data);
- BKE_library_foreach_ID_link(
- id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ for (ID *id_curr = lb_array[i]->first; id_curr; id_curr = id_curr->next) {
+ if (BKE_library_id_can_use_idtype(id_curr, GS(old_id->name))) {
+ /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
+ * the user count handling...
+ * XXX No more true (except for debug usage of those skipping counters). */
+ r_id_remap_data->id = id_curr;
+ libblock_remap_data_preprocess(r_id_remap_data);
+ BKE_library_foreach_ID_link(
+ NULL, id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, foreach_id_flags);
+ }
}
}
}
@@ -522,12 +539,15 @@ void BKE_libblock_remap_locked(
* 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;
+ id_us_clear_real(old_id);
}
- BLI_assert(old_id->us - skipped_refcounted >= 0);
- UNUSED_VARS_NDEBUG(skipped_refcounted);
+ if (old_id->us - skipped_refcounted < 0) {
+ printf("Error in remapping process from '%s' (%p) to '%s' (%p): "
+ "wrong user count in old ID after process (summing up to %d)\n",
+ old_id->name, old_id, new_id ? new_id->name : "<NULL>", new_id, old_id->us - skipped_refcounted);
+ BLI_assert(0);
+ }
if (skipped_direct == 0) {
/* old_id is assumed to not be used directly anymore... */
@@ -542,7 +562,7 @@ void BKE_libblock_remap_locked(
*/
switch (GS(old_id->name)) {
case ID_OB:
- libblock_remap_data_postprocess_object_fromgroup_update(bmain, (Object *)old_id, (Object *)new_id);
+ libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
break;
case ID_GR:
if (!new_id) { /* Only affects us in case group was unlinked. */
@@ -563,8 +583,14 @@ void BKE_libblock_remap_locked(
default:
break;
}
+
/* Node trees may virtually use any kind of data-block... */
+ /* XXX Yuck!!!! nodetree update can do pretty much any thing when talking about py nodes,
+ * including creating new data-blocks (see T50385), so we need to unlock main here. :(
+ * Why can't we have re-entrent locks? */
+ BKE_main_unlock(bmain);
libblock_remap_data_postprocess_nodetree_update(bmain, new_id);
+ BKE_main_lock(bmain);
/* Full rebuild of DAG! */
DAG_relations_tag_update(bmain);
@@ -646,8 +672,7 @@ void BKE_libblock_relink_ex(
switch (GS(old_id->name)) {
case ID_OB:
{
- libblock_remap_data_postprocess_object_fromgroup_update(
- bmain, (Object *)old_id, (Object *)new_id);
+ libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
break;
}
case ID_GR:
@@ -662,7 +687,7 @@ void BKE_libblock_relink_ex(
else {
/* No choice but to check whole objects/groups. */
for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
- libblock_remap_data_postprocess_object_fromgroup_update(bmain, ob, NULL);
+ libblock_remap_data_postprocess_object_update(bmain, ob, NULL);
}
for (Group *grp = bmain->group.first; grp; grp = grp->id.next) {
libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL);
@@ -680,38 +705,52 @@ void BKE_libblock_relink_ex(
}
}
-void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id)
+static int id_relink_to_newid_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cb_flag)
{
- if (id->properties) {
- IDP_FreeProperty(id->properties);
- MEM_freeN(id->properties);
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
+ ID *id = *id_pointer;
+ if (id) {
+ /* See: NEW_ID macro */
+ if (id->newid) {
+ BKE_library_update_ID_link_user(id->newid, id, cb_flag);
+ *id_pointer = id->newid;
+ }
+ else if (id->tag & LIB_TAG_NEW) {
+ id->tag &= ~LIB_TAG_NEW;
+ BKE_libblock_relink_to_newid(id);
+ }
}
+ return IDWALK_RET_NOP;
}
-/**
- * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c
+/** Similar to libblock_relink_ex, but is remapping IDs to their newid value if non-NULL, in given \a id.
*
- * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv.
- * (only applies to main database)
- * \param do_ui_user: similar to do_id_user but makes sure UI does not hold references to
- * \a id.
+ * Very specific usage, not sure we'll keep it on the long run, currently only used in Object duplication code...
*/
-void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user)
+void BKE_libblock_relink_to_newid(ID *id)
{
- ID *id = idv;
- short type = GS(id->name);
- ListBase *lb = which_libbase(bmain, type);
-
- DAG_id_type_tag(bmain, type);
+ if (ID_IS_LINKED_DATABLOCK(id))
+ return;
-#ifdef WITH_PYTHON
- BPY_id_release(id);
-#endif
+ BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0);
+}
- if (do_id_user) {
- BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
+void BKE_libblock_free_data(ID *id, const bool do_id_user)
+{
+ if (id->properties) {
+ IDP_FreeProperty_ex(id->properties, do_id_user);
+ MEM_freeN(id->properties);
}
+ /* XXX TODO remove animdata handling from each type's freeing func, and do it here, like for copy! */
+}
+
+void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
+{
+ const short type = GS(id->name);
switch (type) {
case ID_SCE:
BKE_scene_free((Scene *)id);
@@ -817,6 +856,117 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b
BKE_cachefile_free((CacheFile *)id);
break;
}
+}
+
+
+void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_idtag)
+{
+ ID *id = idv;
+
+ if (use_flag_from_idtag) {
+ if ((id->tag & LIB_TAG_NO_MAIN) != 0) {
+ flag |= LIB_ID_FREE_NO_MAIN;
+ }
+ else {
+ flag &= ~LIB_ID_FREE_NO_MAIN;
+ }
+
+ if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) {
+ flag |= LIB_ID_FREE_NO_USER_REFCOUNT;
+ }
+ else {
+ flag &= ~LIB_ID_FREE_NO_USER_REFCOUNT;
+ }
+
+ if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) {
+ flag |= LIB_ID_FREE_NOT_ALLOCATED;
+ }
+ else {
+ flag &= ~LIB_ID_FREE_NOT_ALLOCATED;
+ }
+ }
+
+ BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || bmain != NULL);
+ BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NOT_ALLOCATED) == 0);
+ BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0);
+
+ const short type = GS(id->name);
+
+ if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) {
+ DAG_id_type_tag(bmain, type);
+ }
+
+#ifdef WITH_PYTHON
+ BPY_id_release(id);
+#endif
+
+ if ((flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0) {
+ BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
+ }
+
+ BKE_libblock_free_datablock(id, flag);
+
+ /* avoid notifying on removed data */
+ if (bmain) {
+ BKE_main_lock(bmain);
+ }
+
+ if ((flag & LIB_ID_FREE_NO_UI_USER) == 0) {
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(id);
+ }
+
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(id, NULL);
+ }
+ }
+
+ if ((flag & LIB_ID_FREE_NO_MAIN) == 0) {
+ ListBase *lb = which_libbase(bmain, type);
+ BLI_remlink(lb, id);
+ }
+
+ BKE_libblock_free_data(id, (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0);
+
+ if (bmain) {
+ BKE_main_unlock(bmain);
+ }
+
+ if ((flag & LIB_ID_FREE_NOT_ALLOCATED) == 0) {
+ MEM_freeN(id);
+ }
+}
+
+void BKE_id_free(Main *bmain, void *idv)
+{
+ BKE_id_free_ex(bmain, idv, 0, true);
+}
+
+/**
+ * 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.
+ * (only applies to main database)
+ * \param do_ui_user: similar to do_id_user but makes sure UI does not hold references to
+ * \a id.
+ */
+void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const bool do_ui_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(bmain, id, NULL, NULL, true);
+ }
+
+ BKE_libblock_free_datablock(id, 0);
/* avoid notifying on removed data */
BKE_main_lock(bmain);
@@ -833,7 +983,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b
BLI_remlink(lb, id);
- BKE_libblock_free_data(bmain, id);
+ BKE_libblock_free_data(id, do_id_user);
BKE_main_unlock(bmain);
MEM_freeN(id);
@@ -854,9 +1004,10 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
* 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.
+ * But only for local objects, not linked ones!
* 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)) {
+ if ((GS(id->name) == ID_OB) && (id->us == 1) && (id->lib == NULL)) {
id_us_clear_real(id);
}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index bd21215f91e..1b1a12e702a 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -41,6 +41,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
@@ -118,7 +119,7 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name)
{
FreestyleLineStyle *linestyle;
- linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name);
+ linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name, 0);
BKE_linestyle_init(linestyle);
@@ -154,73 +155,54 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle)
BKE_linestyle_geometry_modifier_remove(linestyle, m);
}
-FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle)
+/**
+ * Only copy internal data of Linestyle ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_linestyle_copy_data(
+ struct Main *bmain, FreestyleLineStyle *linestyle_dst, const FreestyleLineStyle *linestyle_src, const int flag)
{
- FreestyleLineStyle *new_linestyle;
- LineStyleModifier *m;
- int a;
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
- new_linestyle = BKE_linestyle_new(bmain, linestyle->id.name + 2);
- BKE_linestyle_free(new_linestyle);
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (linestyle->mtex[a]) {
- new_linestyle->mtex[a] = MEM_mallocN(sizeof(MTex), "BKE_linestyle_copy");
- memcpy(new_linestyle->mtex[a], linestyle->mtex[a], sizeof(MTex));
- id_us_plus((ID *)new_linestyle->mtex[a]->tex);
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (linestyle_src->mtex[a]) {
+ linestyle_dst->mtex[a] = MEM_mallocN(sizeof(*linestyle_dst->mtex[a]), __func__);
+ *linestyle_dst->mtex[a] = *linestyle_src->mtex[a];
}
}
- if (linestyle->nodetree) {
- new_linestyle->nodetree = ntreeCopyTree(bmain, linestyle->nodetree);
+ if (linestyle_src->nodetree) {
+ BKE_id_copy_ex(bmain, (ID *)linestyle_src->nodetree, (ID **)&linestyle_dst->nodetree, flag, false);
}
- new_linestyle->r = linestyle->r;
- new_linestyle->g = linestyle->g;
- new_linestyle->b = linestyle->b;
- new_linestyle->alpha = linestyle->alpha;
- new_linestyle->thickness = linestyle->thickness;
- new_linestyle->thickness_position = linestyle->thickness_position;
- new_linestyle->thickness_ratio = linestyle->thickness_ratio;
- new_linestyle->flag = linestyle->flag;
- new_linestyle->caps = linestyle->caps;
- new_linestyle->chaining = linestyle->chaining;
- new_linestyle->rounds = linestyle->rounds;
- new_linestyle->split_length = linestyle->split_length;
- new_linestyle->min_angle = linestyle->min_angle;
- new_linestyle->max_angle = linestyle->max_angle;
- new_linestyle->min_length = linestyle->min_length;
- new_linestyle->max_length = linestyle->max_length;
- new_linestyle->chain_count = linestyle->chain_count;
- new_linestyle->split_dash1 = linestyle->split_dash1;
- new_linestyle->split_gap1 = linestyle->split_gap1;
- new_linestyle->split_dash2 = linestyle->split_dash2;
- new_linestyle->split_gap2 = linestyle->split_gap2;
- new_linestyle->split_dash3 = linestyle->split_dash3;
- new_linestyle->split_gap3 = linestyle->split_gap3;
- new_linestyle->dash1 = linestyle->dash1;
- new_linestyle->gap1 = linestyle->gap1;
- new_linestyle->dash2 = linestyle->dash2;
- new_linestyle->gap2 = linestyle->gap2;
- new_linestyle->dash3 = linestyle->dash3;
- new_linestyle->gap3 = linestyle->gap3;
- new_linestyle->panel = linestyle->panel;
- new_linestyle->sort_key = linestyle->sort_key;
- new_linestyle->integration_type = linestyle->integration_type;
- new_linestyle->texstep = linestyle->texstep;
- new_linestyle->pr_texture = linestyle->pr_texture;
- new_linestyle->use_nodes = linestyle->use_nodes;
- for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next)
- BKE_linestyle_color_modifier_copy(new_linestyle, m);
- for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next)
- BKE_linestyle_alpha_modifier_copy(new_linestyle, m);
- for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next)
- BKE_linestyle_thickness_modifier_copy(new_linestyle, m);
- for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next)
- BKE_linestyle_geometry_modifier_copy(new_linestyle, m);
-
- BKE_id_copy_ensure_local(bmain, &linestyle->id, &new_linestyle->id);
-
- return new_linestyle;
+ LineStyleModifier *m;
+ BLI_listbase_clear(&linestyle_dst->color_modifiers);
+ for (m = (LineStyleModifier *)linestyle_src->color_modifiers.first; m; m = m->next) {
+ BKE_linestyle_color_modifier_copy(linestyle_dst, m, flag_subdata);
+ }
+ BLI_listbase_clear(&linestyle_dst->alpha_modifiers);
+ for (m = (LineStyleModifier *)linestyle_src->alpha_modifiers.first; m; m = m->next) {
+ BKE_linestyle_alpha_modifier_copy(linestyle_dst, m, flag_subdata);
+ }
+ BLI_listbase_clear(&linestyle_dst->thickness_modifiers);
+ for (m = (LineStyleModifier *)linestyle_src->thickness_modifiers.first; m; m = m->next) {
+ BKE_linestyle_thickness_modifier_copy(linestyle_dst, m, flag_subdata);
+ }
+ BLI_listbase_clear(&linestyle_dst->geometry_modifiers);
+ for (m = (LineStyleModifier *)linestyle_src->geometry_modifiers.first; m; m = m->next) {
+ BKE_linestyle_geometry_modifier_copy(linestyle_dst, m, flag_subdata);
+ }
+}
+
+FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineStyle *linestyle)
+{
+ FreestyleLineStyle *linestyle_copy;
+ BKE_id_copy_ex(bmain, &linestyle->id, (ID **)&linestyle_copy, 0, false);
+ return linestyle_copy;
}
void BKE_linestyle_make_local(struct Main *bmain, FreestyleLineStyle *linestyle, const bool lib_local)
@@ -354,7 +336,8 @@ LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyl
return m;
}
-LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_color_modifier_copy(
+ FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag)
{
LineStyleModifier *new_m;
@@ -387,9 +370,10 @@ LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linesty
{
LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)m;
LineStyleColorModifier_DistanceFromObject *q = (LineStyleColorModifier_DistanceFromObject *)new_m;
- if (p->target)
- id_us_plus(&p->target->id);
q->target = p->target;
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)q->target);
+ }
q->color_ramp = MEM_dupallocN(p->color_ramp);
q->range_min = p->range_min;
q->range_max = p->range_max;
@@ -593,7 +577,8 @@ LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyl
return m;
}
-LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_alpha_modifier_copy(
+ FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int UNUSED(flag))
{
LineStyleModifier *new_m;
@@ -862,7 +847,8 @@ LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *line
return m;
}
-LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_thickness_modifier_copy(
+ FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag)
{
LineStyleModifier *new_m;
@@ -900,9 +886,10 @@ LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *lin
{
LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)m;
LineStyleThicknessModifier_DistanceFromObject *q = (LineStyleThicknessModifier_DistanceFromObject *)new_m;
- if (p->target)
- id_us_plus(&p->target->id);
q->target = p->target;
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)q->target);
+ }
q->curve = curvemapping_copy(p->curve);
q->flags = p->flags;
q->range_min = p->range_min;
@@ -1194,7 +1181,8 @@ LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *lines
return m;
}
-LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_geometry_modifier_copy(
+ FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int UNUSED(flag))
{
LineStyleModifier *new_m;
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 21023d9f53c..8b8b48db279 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -36,8 +36,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -51,6 +51,7 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -192,7 +193,7 @@ void BKE_mask_layer_rename(Mask *mask, MaskLayer *masklay, char *oldname, char *
BKE_animdata_fix_paths_rename_all(&mask->id, "layers", oldname, masklay->name);
}
-MaskLayer *BKE_mask_layer_copy(MaskLayer *masklay)
+MaskLayer *BKE_mask_layer_copy(const MaskLayer *masklay)
{
MaskLayer *masklay_new;
MaskSpline *spline;
@@ -236,7 +237,7 @@ MaskLayer *BKE_mask_layer_copy(MaskLayer *masklay)
return masklay_new;
}
-void BKE_mask_layer_copy_list(ListBase *masklayers_new, ListBase *masklayers)
+void BKE_mask_layer_copy_list(ListBase *masklayers_new, const ListBase *masklayers)
{
MaskLayer *layer;
@@ -794,7 +795,7 @@ static Mask *mask_alloc(Main *bmain, const char *name)
{
Mask *mask;
- mask = BKE_libblock_alloc(bmain, ID_MSK, name);
+ mask = BKE_libblock_alloc(bmain, ID_MSK, name, 0);
id_fake_user_set(&mask->id);
@@ -817,10 +818,13 @@ Mask *BKE_mask_new(Main *bmain, const char *name)
mask->sfra = 1;
mask->efra = 100;
+ DAG_relations_tag_update(bmain);
+
return mask;
}
/* TODO(sergey): Use generic BKE_libblock_copy_nolib() instead. */
+/* TODO(bastien): Use new super cool & generic BKE_id_copy_ex() instead! */
Mask *BKE_mask_copy_nolib(Mask *mask)
{
Mask *mask_new;
@@ -840,22 +844,29 @@ Mask *BKE_mask_copy_nolib(Mask *mask)
return mask_new;
}
-Mask *BKE_mask_copy(Main *bmain, Mask *mask)
+/**
+ * Only copy internal data of Mask ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_mask_copy_data(Main *UNUSED(bmain), Mask *mask_dst, const Mask *mask_src, const int UNUSED(flag))
{
- Mask *mask_new;
-
- mask_new = BKE_libblock_copy(bmain, &mask->id);
+ BLI_listbase_clear(&mask_dst->masklayers);
- BLI_listbase_clear(&mask_new->masklayers);
-
- BKE_mask_layer_copy_list(&mask_new->masklayers, &mask->masklayers);
+ BKE_mask_layer_copy_list(&mask_dst->masklayers, &mask_src->masklayers); /* TODO add unused flag to those as well. */
/* enable fake user by default */
- id_fake_user_set(&mask->id);
-
- BKE_id_copy_ensure_local(bmain, &mask->id, &mask_new->id);
+ id_fake_user_set(&mask_dst->id);
+}
- return mask_new;
+Mask *BKE_mask_copy(Main *bmain, const Mask *mask)
+{
+ Mask *mask_copy;
+ BKE_id_copy_ex(bmain, &mask->id, (ID **)&mask_copy, 0, false);
+ return mask_copy;
}
void BKE_mask_make_local(Main *bmain, Mask *mask, const bool lib_local)
@@ -906,7 +917,7 @@ void BKE_mask_spline_free_list(ListBase *splines)
}
}
-static MaskSplinePoint *mask_spline_points_copy(MaskSplinePoint *points, int tot_point)
+static MaskSplinePoint *mask_spline_points_copy(const MaskSplinePoint *points, int tot_point)
{
MaskSplinePoint *npoints;
int i;
@@ -923,7 +934,7 @@ static MaskSplinePoint *mask_spline_points_copy(MaskSplinePoint *points, int tot
return npoints;
}
-MaskSpline *BKE_mask_spline_copy(MaskSpline *spline)
+MaskSpline *BKE_mask_spline_copy(const MaskSpline *spline)
{
MaskSpline *nspline = MEM_callocN(sizeof(MaskSpline), "new spline");
@@ -1171,17 +1182,6 @@ void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point, float ctime, float
}
}
-static void mask_evaluate_apply_point_parent(MaskSplinePoint *point, float ctime)
-{
- float parent_matrix[3][3];
-
- BKE_mask_point_parent_matrix_get(point, ctime, parent_matrix);
-
- mul_m3_v2(parent_matrix, point->bezt.vec[0]);
- mul_m3_v2(parent_matrix, point->bezt.vec[1]);
- mul_m3_v2(parent_matrix, point->bezt.vec[2]);
-}
-
static void mask_calc_point_handle(MaskSplinePoint *point, MaskSplinePoint *point_prev, MaskSplinePoint *point_next)
{
BezTriple *bezt = &point->bezt;
@@ -1397,80 +1397,12 @@ void BKE_mask_spline_ensure_deform(MaskSpline *spline)
void BKE_mask_layer_evaluate(MaskLayer *masklay, const float ctime, const bool do_newframe)
{
- /* animation if available */
+ /* Animation if available. */
if (do_newframe) {
- MaskLayerShape *masklay_shape_a;
- MaskLayerShape *masklay_shape_b;
- int found;
-
- if ((found = BKE_mask_layer_shape_find_frame_range(masklay, ctime,
- &masklay_shape_a, &masklay_shape_b)))
- {
- if (found == 1) {
-#if 0
- printf("%s: exact %d %d (%d)\n", __func__, (int)ctime, BLI_listbase_count(&masklay->splines_shapes),
- masklay_shape_a->frame);
-#endif
-
- BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a);
- }
- else if (found == 2) {
- float w = masklay_shape_b->frame - masklay_shape_a->frame;
-#if 0
- printf("%s: tween %d %d (%d %d)\n", __func__, (int)ctime, BLI_listbase_count(&masklay->splines_shapes),
- masklay_shape_a->frame, masklay_shape_b->frame);
-#endif
- BKE_mask_layer_shape_to_mask_interp(masklay, masklay_shape_a, masklay_shape_b,
- (ctime - masklay_shape_a->frame) / w);
- }
- else {
- /* always fail, should never happen */
- BLI_assert(found == 2);
- }
- }
- }
- /* animation done... */
-
- BKE_mask_layer_calc_handles(masklay);
-
- /* update deform */
- {
- MaskSpline *spline;
-
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- int i;
- bool need_handle_recalc = false;
-
- BKE_mask_spline_ensure_deform(spline);
-
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &spline->points[i];
- MaskSplinePoint *point_deform = &spline->points_deform[i];
-
- BKE_mask_point_free(point_deform);
-
- *point_deform = *point;
- point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL;
-
- mask_evaluate_apply_point_parent(point_deform, ctime);
-
- if (ELEM(point->bezt.h1, HD_AUTO, HD_VECT)) {
- need_handle_recalc = true;
- }
- }
-
- /* if the spline has auto or vector handles, these need to be recalculated after deformation */
- if (need_handle_recalc) {
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point_deform = &spline->points_deform[i];
- if (ELEM(point_deform->bezt.h1, HD_AUTO, HD_VECT)) {
- BKE_mask_calc_handle_point(spline, point_deform);
- }
- }
- }
- /* end extra calc handles loop */
- }
+ BKE_mask_layer_evaluate_animation(masklay, ctime);
}
+ /* Update deform. */
+ BKE_mask_layer_evaluate_deform(masklay, ctime);
}
void BKE_mask_evaluate(Mask *mask, const float ctime, const bool do_newframe)
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index 1b275f455f4..0d71cc548c7 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -42,6 +42,8 @@
#include "DNA_mask_types.h"
#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_mask.h"
@@ -810,3 +812,111 @@ float *BKE_mask_point_segment_diff(MaskSpline *spline, MaskSplinePoint *point,
return diff_points;
}
+
+static void mask_evaluate_apply_point_parent(MaskSplinePoint *point, float ctime)
+{
+ float parent_matrix[3][3];
+ BKE_mask_point_parent_matrix_get(point, ctime, parent_matrix);
+ mul_m3_v2(parent_matrix, point->bezt.vec[0]);
+ mul_m3_v2(parent_matrix, point->bezt.vec[1]);
+ mul_m3_v2(parent_matrix, point->bezt.vec[2]);
+}
+
+void BKE_mask_layer_evaluate_animation(MaskLayer *masklay, const float ctime)
+{
+ /* animation if available */
+ MaskLayerShape *masklay_shape_a;
+ MaskLayerShape *masklay_shape_b;
+ int found;
+ if ((found = BKE_mask_layer_shape_find_frame_range(
+ masklay, ctime, &masklay_shape_a, &masklay_shape_b)))
+ {
+ if (found == 1) {
+#if 0
+ printf("%s: exact %d %d (%d)\n",
+ __func__,
+ (int)ctime,
+ BLI_listbase_count(&masklay->splines_shapes),
+ masklay_shape_a->frame);
+#endif
+ BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a);
+ }
+ else if (found == 2) {
+ float w = masklay_shape_b->frame - masklay_shape_a->frame;
+#if 0
+ printf("%s: tween %d %d (%d %d)\n",
+ __func__,
+ (int)ctime,
+ BLI_listbase_count(&masklay->splines_shapes),
+ masklay_shape_a->frame, masklay_shape_b->frame);
+#endif
+ BKE_mask_layer_shape_to_mask_interp(
+ masklay,
+ masklay_shape_a, masklay_shape_b,
+ (ctime - masklay_shape_a->frame) / w);
+ }
+ else {
+ /* always fail, should never happen */
+ BLI_assert(found == 2);
+ }
+ }
+}
+
+void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime)
+{
+ BKE_mask_layer_calc_handles(masklay);
+ for (MaskSpline *spline = masklay->splines.first;
+ spline != NULL;
+ spline = spline->next)
+ {
+ bool need_handle_recalc = false;
+ BKE_mask_spline_ensure_deform(spline);
+ for (int i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &spline->points[i];
+ MaskSplinePoint *point_deform = &spline->points_deform[i];
+ BKE_mask_point_free(point_deform);
+ *point_deform = *point;
+ point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL;
+ mask_evaluate_apply_point_parent(point_deform, ctime);
+ if (ELEM(point->bezt.h1, HD_AUTO, HD_VECT)) {
+ need_handle_recalc = true;
+ }
+ }
+ /* if the spline has auto or vector handles, these need to be
+ * recalculated after deformation.
+ */
+ if (need_handle_recalc) {
+ for (int i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point_deform = &spline->points_deform[i];
+ if (ELEM(point_deform->bezt.h1, HD_AUTO, HD_VECT)) {
+ BKE_mask_calc_handle_point(spline, point_deform);
+ }
+ }
+ }
+ /* end extra calc handles loop */
+ }
+}
+
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+
+void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask)
+{
+ DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask);
+ for (MaskLayer *mask_layer = mask->masklayers.first;
+ mask_layer != NULL;
+ mask_layer = mask_layer->next)
+ {
+ BKE_mask_layer_evaluate_animation(mask_layer, eval_ctx->ctime);
+ }
+}
+
+void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, Mask *mask)
+{
+ DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask);
+ for (MaskLayer *mask_layer = mask->masklayers.first;
+ mask_layer != NULL;
+ mask_layer = mask_layer->next)
+ {
+ BKE_mask_layer_evaluate_deform(mask_layer, eval_ctx->ctime);
+ }
+}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 54945242fe4..f5be72c6b4d 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -212,50 +212,68 @@ Material *BKE_material_add(Main *bmain, const char *name)
{
Material *ma;
- ma = BKE_libblock_alloc(bmain, ID_MA, name);
+ ma = BKE_libblock_alloc(bmain, ID_MA, name, 0);
BKE_material_init(ma);
return ma;
}
-/* XXX keep synced with next function */
-Material *BKE_material_copy(Main *bmain, Material *ma)
+/**
+ * Only copy internal data of Material ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_src, const int flag)
{
- Material *man;
- int a;
-
- man = BKE_libblock_copy(bmain, &ma->id);
-
- id_lib_extern((ID *)man->group);
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- man->mtex[a] = MEM_mallocN(sizeof(MTex), "copymaterial");
- memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex));
- id_us_plus((ID *)man->mtex[a]->tex);
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (ma_src->mtex[a]) {
+ ma_dst->mtex[a] = MEM_mallocN(sizeof(*ma_dst->mtex[a]), __func__);
+ *ma_dst->mtex[a] = *ma_src->mtex[a];
}
}
-
- if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col);
- if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec);
-
- if (ma->nodetree) {
- man->nodetree = ntreeCopyTree(bmain, ma->nodetree);
+
+ if (ma_src->ramp_col) {
+ ma_dst->ramp_col = MEM_dupallocN(ma_src->ramp_col);
+ }
+ if (ma_src->ramp_spec) {
+ ma_dst->ramp_spec = MEM_dupallocN(ma_src->ramp_spec);
}
- BKE_previewimg_id_copy(&man->id, &ma->id);
+ if (ma_src->nodetree) {
+ BKE_id_copy_ex(bmain, (ID *)ma_src->nodetree, (ID **)&ma_dst->nodetree, flag, false);
+ }
- BLI_listbase_clear(&man->gpumaterial);
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&ma_dst->id, &ma_src->id);
+ }
+ else {
+ ma_dst->preview = NULL;
+ }
- BKE_id_copy_ensure_local(bmain, &ma->id, &man->id);
+ BLI_listbase_clear(&ma_dst->gpumaterial);
+}
- return man;
+Material *BKE_material_copy(Main *bmain, const Material *ma)
+{
+ Material *ma_copy;
+ BKE_id_copy_ex(bmain, &ma->id, (ID **)&ma_copy, 0, false);
+ return ma_copy;
}
/* XXX (see above) material copy without adding to main dbase */
Material *localize_material(Material *ma)
{
+ /* TODO replace with something like
+ * Material *ma_copy;
+ * BKE_id_copy_ex(bmain, &ma->id, (ID **)&ma_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false);
+ * return ma_copy;
+ *
+ * ... Once f*** nodes are fully converted to that too :( */
+
Material *man;
int a;
@@ -343,6 +361,8 @@ Material ***give_matarar_id(ID *id)
return &(((Curve *)id)->mat);
case ID_MB:
return &(((MetaBall *)id)->mat);
+ default:
+ break;
}
return NULL;
}
@@ -359,6 +379,8 @@ short *give_totcolp_id(ID *id)
return &(((Curve *)id)->totcol);
case ID_MB:
return &(((MetaBall *)id)->totcol);
+ default:
+ break;
}
return NULL;
}
@@ -378,6 +400,8 @@ static void material_data_index_remove_id(ID *id, short index)
case ID_MB:
/* meta-elems don't have materials atm */
break;
+ default:
+ break;
}
}
@@ -396,6 +420,8 @@ static void material_data_index_clear_id(ID *id)
case ID_MB:
/* meta-elems don't have materials atm */
break;
+ default:
+ break;
}
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 8d024ea9aa5..dfc49c996b1 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -49,6 +49,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
@@ -95,33 +96,36 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name)
{
MetaBall *mb;
- mb = BKE_libblock_alloc(bmain, ID_MB, name);
+ mb = BKE_libblock_alloc(bmain, ID_MB, name, 0);
BKE_mball_init(mb);
return mb;
}
-MetaBall *BKE_mball_copy(Main *bmain, MetaBall *mb)
+/**
+ * Only copy internal data of MetaBall ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_mball_copy_data(Main *UNUSED(bmain), MetaBall *mb_dst, const MetaBall *mb_src, const int UNUSED(flag))
{
- MetaBall *mbn;
- int a;
-
- mbn = BKE_libblock_copy(bmain, &mb->id);
+ BLI_duplicatelist(&mb_dst->elems, &mb_src->elems);
- BLI_duplicatelist(&mbn->elems, &mb->elems);
-
- mbn->mat = MEM_dupallocN(mb->mat);
- for (a = 0; a < mbn->totcol; a++) {
- id_us_plus((ID *)mbn->mat[a]);
- }
+ mb_dst->mat = MEM_dupallocN(mb_src->mat);
- mbn->editelems = NULL;
- mbn->lastelem = NULL;
-
- BKE_id_copy_ensure_local(bmain, &mb->id, &mbn->id);
+ mb_dst->editelems = NULL;
+ mb_dst->lastelem = NULL;
+}
- return mbn;
+MetaBall *BKE_mball_copy(Main *bmain, const MetaBall *mb)
+{
+ MetaBall *mb_copy;
+ BKE_id_copy_ex(bmain, &mb->id, (ID **)&mb_copy, 0, false);
+ return mb_copy;
}
void BKE_mball_make_local(Main *bmain, MetaBall *mb, const bool lib_local)
@@ -469,7 +473,7 @@ bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3])
return false;
}
-void BKE_mball_transform(MetaBall *mb, float mat[4][4])
+void BKE_mball_transform(MetaBall *mb, float mat[4][4], const bool do_props)
{
MetaElem *me;
float quat[4];
@@ -481,14 +485,17 @@ void BKE_mball_transform(MetaBall *mb, float mat[4][4])
for (me = mb->elems.first; me; me = me->next) {
mul_m4_v3(mat, &me->x);
mul_qt_qtqt(me->quat, quat, me->quat);
- me->rad *= scale;
- /* hrmf, probably elems shouldn't be
- * treating scale differently - campbell */
- if (!MB_TYPE_SIZE_SQUARED(me->type)) {
- mul_v3_fl(&me->expx, scale);
- }
- else {
- mul_v3_fl(&me->expx, scale_sqrt);
+
+ if (do_props) {
+ me->rad *= scale;
+ /* hrmf, probably elems shouldn't be
+ * treating scale differently - campbell */
+ if (!MB_TYPE_SIZE_SQUARED(me->type)) {
+ mul_v3_fl(&me->expx, scale);
+ }
+ else {
+ mul_v3_fl(&me->expx, scale_sqrt);
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 2068854421f..82d82ce71c4 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -41,8 +41,8 @@
#include "DNA_scene_types.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_memarena.h"
@@ -316,12 +316,12 @@ static float densfunc(const MetaElem *ball, float x, float y, float z)
if (dvec[2] > ball->expz) dvec[2] -= ball->expz;
else if (dvec[2] < -ball->expz) dvec[2] += ball->expz;
else dvec[2] = 0.0;
- /* fall through */
+ ATTR_FALLTHROUGH;
case MB_PLANE:
if (dvec[1] > ball->expy) dvec[1] -= ball->expy;
else if (dvec[1] < -ball->expy) dvec[1] += ball->expy;
else dvec[1] = 0.0;
- /* fall through */
+ ATTR_FALLTHROUGH;
case MB_TUBE:
if (dvec[0] > ball->expx) dvec[0] -= ball->expx;
else if (dvec[0] < -ball->expx) dvec[0] += ball->expx;
@@ -423,13 +423,13 @@ static void make_face(PROCESS *process, int i1, int i2, int i3, int i4)
#ifdef USE_ACCUM_NORMAL
if (i4 == 0) {
normal_tri_v3(n, process->co[i1], process->co[i2], process->co[i3]);
- accumulate_vertex_normals(
+ accumulate_vertex_normals_v3(
process->no[i1], process->no[i2], process->no[i3], NULL, n,
process->co[i1], process->co[i2], process->co[i3], NULL);
}
else {
normal_quad_v3(n, process->co[i1], process->co[i2], process->co[i3], process->co[i4]);
- accumulate_vertex_normals(
+ accumulate_vertex_normals_v3(
process->no[i1], process->no[i2], process->no[i3], process->no[i4], n,
process->co[i1], process->co[i2], process->co[i3], process->co[i4]);
}
@@ -660,7 +660,7 @@ static void makecubetable(void)
for (i = 0; i < 256; i++) {
for (e = 0; e < 12; e++) done[e] = 0;
for (c = 0; c < 8; c++) pos[c] = MB_BIT(i, c);
- for (e = 0; e < 12; e++)
+ for (e = 0; e < 12; e++) {
if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
INTLIST *ints = NULL;
INTLISTS *lists = MEM_callocN(sizeof(INTLISTS), "mball_intlist");
@@ -687,6 +687,7 @@ static void makecubetable(void)
lists->next = cubetable[i];
cubetable[i] = lists;
}
+ }
}
for (i = 0; i < 256; i++) {
@@ -1193,10 +1194,10 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen
break;
case MB_CUBE: /* cube is "expanded" by expz, expy and expx */
expz += ml->expz;
- /* fall through */
+ ATTR_FALLTHROUGH;
case MB_PLANE: /* plane is "expanded" by expy and expx */
expy += ml->expy;
- /* fall through */
+ ATTR_FALLTHROUGH;
case MB_TUBE: /* tube is "expanded" by expx */
expx += ml->expx;
break;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index d21f43ac484..0d01fe77453 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -39,7 +39,9 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_linklist.h"
#include "BLI_listbase.h"
+#include "BLI_memarena.h"
#include "BLI_edgehash.h"
#include "BLI_string.h"
@@ -66,6 +68,11 @@
#include "DEG_depsgraph.h"
+/* Define for cases when you want extra validation of mesh
+ * after certain modifications.
+ */
+// #undef VALIDATE_MESH
+
enum {
MESHCMP_DVERT_WEIGHTMISMATCH = 1,
MESHCMP_DVERT_GROUPMISMATCH,
@@ -487,53 +494,56 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
{
Mesh *me;
- me = BKE_libblock_alloc(bmain, ID_ME, name);
+ me = BKE_libblock_alloc(bmain, ID_ME, name, 0);
BKE_mesh_init(me);
return me;
}
-Mesh *BKE_mesh_copy(Main *bmain, Mesh *me)
+/**
+ * Only copy internal data of Mesh ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int flag)
{
- Mesh *men;
- int a;
- const int do_tessface = ((me->totface != 0) && (me->totpoly == 0)); /* only do tessface if we have no polys */
-
- men = BKE_libblock_copy(bmain, &me->id);
-
- men->mat = MEM_dupallocN(me->mat);
- for (a = 0; a < men->totcol; a++) {
- id_us_plus((ID *)men->mat[a]);
- }
- id_us_plus((ID *)men->texcomesh);
+ const bool do_tessface = ((me_src->totface != 0) && (me_src->totpoly == 0)); /* only do tessface if we have no polys */
+
+ me_dst->mat = MEM_dupallocN(me_src->mat);
- CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert);
- CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge);
- CustomData_copy(&me->ldata, &men->ldata, CD_MASK_MESH, CD_DUPLICATE, men->totloop);
- CustomData_copy(&me->pdata, &men->pdata, CD_MASK_MESH, CD_DUPLICATE, men->totpoly);
+ CustomData_copy(&me_src->vdata, &me_dst->vdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totvert);
+ CustomData_copy(&me_src->edata, &me_dst->edata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totedge);
+ CustomData_copy(&me_src->ldata, &me_dst->ldata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totloop);
+ CustomData_copy(&me_src->pdata, &me_dst->pdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totpoly);
if (do_tessface) {
- CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface);
+ CustomData_copy(&me_src->fdata, &me_dst->fdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totface);
}
else {
- mesh_tessface_clear_intern(men, false);
+ mesh_tessface_clear_intern(me_dst, false);
}
- BKE_mesh_update_customdata_pointers(men, do_tessface);
+ BKE_mesh_update_customdata_pointers(me_dst, do_tessface);
- men->edit_btmesh = NULL;
+ me_dst->edit_btmesh = NULL;
- men->mselect = MEM_dupallocN(men->mselect);
- men->bb = MEM_dupallocN(men->bb);
+ me_dst->mselect = MEM_dupallocN(me_dst->mselect);
+ me_dst->bb = MEM_dupallocN(me_dst->bb);
- if (me->key) {
- men->key = BKE_key_copy(bmain, me->key);
- men->key->from = (ID *)men;
+ /* TODO Do we want to add flag to prevent this? */
+ if (me_src->key) {
+ BKE_id_copy_ex(bmain, &me_src->key->id, (ID **)&me_dst->key, flag, false);
}
+}
- BKE_id_copy_ensure_local(bmain, &me->id, &men->id);
-
- return men;
+Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me)
+{
+ Mesh *me_copy;
+ BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, 0, false);
+ return me_copy;
}
BMesh *BKE_mesh_to_bmesh(
@@ -1332,7 +1342,7 @@ int BKE_mesh_nurbs_displist_to_mdata(
/* this may fail replacing ob->data, be sure to check ob->type */
-void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use_orco_uv)
+void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name)
{
Main *bmain = G.main;
Object *ob1;
@@ -1359,7 +1369,7 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
}
/* make mesh */
- me = BKE_mesh_add(bmain, "Mesh");
+ me = BKE_mesh_add(bmain, obdata_name);
me->totvert = totvert;
me->totedge = totedge;
me->totloop = totloop;
@@ -1379,7 +1389,7 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
BKE_mesh_calc_normals(me);
}
else {
- me = BKE_mesh_add(bmain, "Mesh");
+ me = BKE_mesh_add(bmain, obdata_name);
DM_to_mesh(dm, me, ob, CD_MASK_MESH, false);
}
@@ -1391,9 +1401,7 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
cu->mat = NULL;
cu->totcol = 0;
- if (ob->data) {
- BKE_libblock_free(bmain, ob->data);
- }
+ /* Do not decrement ob->data usercount here, it's done at end of func with BKE_libblock_free_us() call. */
ob->data = me;
ob->type = OB_MESH;
@@ -1403,11 +1411,14 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
if (ob1->data == cu) {
ob1->type = OB_MESH;
+ id_us_min((ID *)ob1->data);
ob1->data = ob->data;
- id_us_plus((ID *)ob->data);
+ id_us_plus((ID *)ob1->data);
}
ob1 = ob1->id.next;
}
+
+ BKE_libblock_free_us(bmain, cu);
}
void BKE_mesh_from_nurbs(Object *ob)
@@ -1420,7 +1431,7 @@ void BKE_mesh_from_nurbs(Object *ob)
disp = ob->curve_cache->disp;
}
- BKE_mesh_from_nurbs_displist(ob, &disp, use_orco_uv);
+ BKE_mesh_from_nurbs_displist(ob, &disp, use_orco_uv, cu->id.name);
}
typedef struct EdgeLink {
@@ -2048,13 +2059,24 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
(me->mselect[me->totselect - 1].type == type));
}
-void BKE_mesh_calc_normals_split(Mesh *mesh)
+/**
+ * Compute 'split' (aka loop, or per face corner's) normals.
+ *
+ * \param r_lnors_spacearr Allows to get computed loop normal space array. That data, among other things,
+ * contains 'smooth fan' info, useful e.g. to split geometry along sharp edges...
+ */
+void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
{
float (*r_loopnors)[3];
float (*polynors)[3];
short (*clnors)[2] = NULL;
bool free_polynors = false;
+ /* Note that we enforce computing clnors when the clnor space array is requested by caller here.
+ * However, we obviously only use the autosmooth angle threshold only in case autosmooth is enabled. */
+ const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0);
+ const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI;
+
if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
@@ -2083,113 +2105,272 @@ void BKE_mesh_calc_normals_split(Mesh *mesh)
BKE_mesh_normals_loop_split(
mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly,
- (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, NULL, clnors, NULL);
+ use_split_normals, split_angle, r_lnors_spacearr, clnors, NULL);
if (free_polynors) {
MEM_freeN(polynors);
}
}
-/* Spli faces based on the edge angle.
- * Matches behavior of face splitting in render engines.
- */
-void BKE_mesh_split_faces(Mesh *mesh)
+void BKE_mesh_calc_normals_split(Mesh *mesh)
{
- const int num_verts = mesh->totvert;
- const int num_edges = mesh->totedge;
- const int num_polys = mesh->totpoly;
+ BKE_mesh_calc_normals_split_ex(mesh, NULL);
+}
+
+/* Split faces helper functions. */
+
+typedef struct SplitFaceNewVert {
+ struct SplitFaceNewVert *next;
+ int new_index;
+ int orig_index;
+ float *vnor;
+} SplitFaceNewVert;
+
+typedef struct SplitFaceNewEdge {
+ struct SplitFaceNewEdge *next;
+ int new_index;
+ int orig_index;
+ int v1;
+ int v2;
+} SplitFaceNewEdge;
+
+/* Detect needed new vertices, and update accordingly loops' vertex indices.
+ * WARNING! Leaves mesh in invalid state. */
+static int split_faces_prepare_new_verts(
+ const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena)
+{
+ /* This is now mandatory, trying to do the job in simple way without that data is doomed to fail, even when only
+ * dealing with smooth/flat faces one can find cases that no simple algorithm can handle properly. */
+ BLI_assert(lnors_spacearr != NULL);
+
+ const int num_loops = mesh->totloop;
+ int num_verts = mesh->totvert;
MVert *mvert = mesh->mvert;
- MEdge *medge = mesh->medge;
MLoop *mloop = mesh->mloop;
- MPoly *mpoly = mesh->mpoly;
- float (*lnors)[3];
- int poly, num_new_verts = 0;
- if ((mesh->flag & ME_AUTOSMOOTH) == 0) {
- return;
- }
- BKE_mesh_tessface_clear(mesh);
- /* Compute loop normals if needed. */
- if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
- BKE_mesh_calc_normals_split(mesh);
- }
- lnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- /* Count number of vertices to be split. */
- for (poly = 0; poly < num_polys; poly++) {
- MPoly *mp = &mpoly[poly];
- int loop;
- for (loop = 0; loop < mp->totloop; loop++) {
- MLoop *ml = &mloop[mp->loopstart + loop];
- MVert *mv = &mvert[ml->v];
- float vn[3];
- normal_short_to_float_v3(vn, mv->no);
- if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
- num_new_verts++;
+
+ BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__);
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__);
+
+ MLoop *ml = mloop;
+ MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
+
+ for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) {
+ if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
+ const int vert_idx = ml->v;
+ const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
+ /* If vert is already used by another smooth fan, we need a new vert for this one. */
+ const int new_vert_idx = vert_used ? num_verts++ : vert_idx;
+
+ BLI_assert(*lnor_space);
+
+ if ((*lnor_space)->loops) {
+ for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) {
+ const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link);
+ BLI_BITMAP_ENABLE(done_loops, ml_fan_idx);
+ if (vert_used) {
+ mloop[ml_fan_idx].v = new_vert_idx;
+ }
+ }
+ }
+ else {
+ /* Single loop in this fan... */
+ BLI_BITMAP_ENABLE(done_loops, loop_idx);
+ if (vert_used) {
+ ml->v = new_vert_idx;
+ }
+ }
+
+ if (!vert_used) {
+ BLI_BITMAP_ENABLE(verts_used, vert_idx);
+ /* We need to update that vertex's normal here, we won't go over it again. */
+ /* This is important! *DO NOT* set vnor to final computed lnor, vnor should always be defined to
+ * 'automatic normal' value computed from its polys, not some custom normal.
+ * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
+ normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
+ }
+ else {
+ /* Add new vert to list. */
+ SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
+ new_vert->orig_index = vert_idx;
+ new_vert->new_index = new_vert_idx;
+ new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */
+ new_vert->next = *new_verts;
+ *new_verts = new_vert;
}
}
}
- if (num_new_verts == 0) {
- /* No new vertices are to be added, can do early exit. */
- return;
- }
- /* Reallocate all vert and edge related data. */
- mesh->totvert += num_new_verts;
- mesh->totedge += 2 * num_new_verts;
- CustomData_realloc(&mesh->vdata, mesh->totvert);
- CustomData_realloc(&mesh->edata, mesh->totedge);
- /* Update pointers to a newly allocated memory. */
- BKE_mesh_update_customdata_pointers(mesh, false);
- mvert = mesh->mvert;
- medge = mesh->medge;
- /* Perform actual vertex split. */
- num_new_verts = 0;
- for (poly = 0; poly < num_polys; poly++) {
- MPoly *mp = &mpoly[poly];
- int loop;
- for (loop = 0; loop < mp->totloop; loop++) {
- int poly_loop = mp->loopstart + loop;
- MLoop *ml = &mloop[poly_loop];
- MVert *mv = &mvert[ml->v];
- float vn[3];
- normal_short_to_float_v3(vn, mv->no);
- if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
- int poly_loop_prev = mp->loopstart + (loop + mp->totloop - 1) % mp->totloop;
- MLoop *ml_prev = &mloop[poly_loop_prev];
- int new_edge_prev, new_edge;
- /* Cretae new vertex. */
- int new_vert = num_verts + num_new_verts;
- CustomData_copy_data(&mesh->vdata, &mesh->vdata,
- ml->v, new_vert, 1);
- normal_float_to_short_v3(mvert[new_vert].no,
- lnors[poly_loop]);
- /* Create new edges. */
- new_edge_prev = num_edges + 2 * num_new_verts;
- new_edge = num_edges + 2 * num_new_verts + 1;
- CustomData_copy_data(&mesh->edata, &mesh->edata,
- ml_prev->e, new_edge_prev, 1);
- CustomData_copy_data(&mesh->edata, &mesh->edata,
- ml->e, new_edge, 1);
- if (medge[new_edge_prev].v1 == ml->v) {
- medge[new_edge_prev].v1 = new_vert;
- }
- else {
- medge[new_edge_prev].v2 = new_vert;
- }
- if (medge[new_edge].v1 == ml->v) {
- medge[new_edge].v1 = new_vert;
+
+ MEM_freeN(done_loops);
+ MEM_freeN(verts_used);
+
+ return num_verts - mesh->totvert;
+}
+
+/* Detect needed new edges, and update accordingly loops' edge indices.
+ * WARNING! Leaves mesh in invalid state. */
+static int split_faces_prepare_new_edges(
+ const Mesh *mesh, SplitFaceNewEdge **new_edges, MemArena *memarena)
+{
+ const int num_polys = mesh->totpoly;
+ int num_edges = mesh->totedge;
+ MEdge *medge = mesh->medge;
+ MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+
+ BLI_bitmap *edges_used = BLI_BITMAP_NEW(num_edges, __func__);
+ EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges);
+
+ const MPoly *mp = mpoly;
+ for (int poly_idx = 0; poly_idx < num_polys; poly_idx++, mp++) {
+ MLoop *ml_prev = &mloop[mp->loopstart + mp->totloop - 1];
+ MLoop *ml = &mloop[mp->loopstart];
+ for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) {
+ void **eval;
+ if (!BLI_edgehash_ensure_p(edges_hash, ml_prev->v, ml->v, &eval)) {
+ const int edge_idx = ml_prev->e;
+
+ /* That edge has not been encountered yet, define it. */
+ if (BLI_BITMAP_TEST(edges_used, edge_idx)) {
+ /* Original edge has already been used, we need to define a new one. */
+ const int new_edge_idx = num_edges++;
+ *eval = SET_INT_IN_POINTER(new_edge_idx);
+ ml_prev->e = new_edge_idx;
+
+ SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge));
+ new_edge->orig_index = edge_idx;
+ new_edge->new_index = new_edge_idx;
+ new_edge->v1 = ml_prev->v;
+ new_edge->v2 = ml->v;
+ new_edge->next = *new_edges;
+ *new_edges = new_edge;
}
else {
- medge[new_edge].v2 = new_vert;
+ /* We can re-use original edge. */
+ medge[edge_idx].v1 = ml_prev->v;
+ medge[edge_idx].v2 = ml->v;
+ *eval = SET_INT_IN_POINTER(edge_idx);
+ BLI_BITMAP_ENABLE(edges_used, edge_idx);
}
-
- ml->v = new_vert;
- ml_prev->e = new_edge_prev;
- ml->e = new_edge;
- num_new_verts++;
}
+ else {
+ /* Edge already known, just update loop's edge index. */
+ ml_prev->e = GET_INT_FROM_POINTER(*eval);
+ }
+
+ ml_prev = ml;
+ }
+ }
+
+ MEM_freeN(edges_used);
+ BLI_edgehash_free(edges_hash, NULL);
+
+ return num_edges - mesh->totedge;
+}
+
+/* Perform actual split of vertices. */
+static void split_faces_split_new_verts(
+ Mesh *mesh, SplitFaceNewVert *new_verts, const int num_new_verts)
+{
+ const int num_verts = mesh->totvert - num_new_verts;
+ MVert *mvert = mesh->mvert;
+
+ /* Remember new_verts is a single linklist, so its items are in reversed order... */
+ MVert *new_mv = &mvert[mesh->totvert - 1];
+ for (int i = mesh->totvert - 1; i >= num_verts ; i--, new_mv--, new_verts = new_verts->next) {
+ BLI_assert(new_verts->new_index == i);
+ BLI_assert(new_verts->new_index != new_verts->orig_index);
+ CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
+ if (new_verts->vnor) {
+ normal_float_to_short_v3(new_mv->no, new_verts->vnor);
}
}
}
+/* Perform actual split of edges. */
+static void split_faces_split_new_edges(
+ Mesh *mesh, SplitFaceNewEdge *new_edges, const int num_new_edges)
+{
+ const int num_edges = mesh->totedge - num_new_edges;
+ MEdge *medge = mesh->medge;
+
+ /* Remember new_edges is a single linklist, so its items are in reversed order... */
+ MEdge *new_med = &medge[mesh->totedge - 1];
+ for (int i = mesh->totedge - 1; i >= num_edges ; i--, new_med--, new_edges = new_edges->next) {
+ BLI_assert(new_edges->new_index == i);
+ BLI_assert(new_edges->new_index != new_edges->orig_index);
+ CustomData_copy_data(&mesh->edata, &mesh->edata, new_edges->orig_index, i, 1);
+ new_med->v1 = new_edges->v1;
+ new_med->v2 = new_edges->v2;
+ }
+}
+
+/* Split faces based on the edge angle and loop normals.
+ * Matches behavior of face splitting in render engines.
+ *
+ * NOTE: Will leave CD_NORMAL loop data layer which is
+ * used by render engines to set shading up.
+ */
+void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
+{
+ const int num_polys = mesh->totpoly;
+
+ if (num_polys == 0) {
+ return;
+ }
+ BKE_mesh_tessface_clear(mesh);
+
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+ /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
+ BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr);
+ /* Stealing memarena from loop normals space array. */
+ MemArena *memarena = lnors_spacearr.mem;
+
+ SplitFaceNewVert *new_verts = NULL;
+ SplitFaceNewEdge *new_edges = NULL;
+
+ /* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */
+ const int num_new_verts = split_faces_prepare_new_verts(mesh, &lnors_spacearr, &new_verts, memarena);
+
+ if (num_new_verts > 0) {
+ /* Reminder: beyond this point, there is no way out, mesh is in invalid state (due to early-reassignment of
+ * loops' vertex and edge indices to new, to-be-created split ones). */
+
+ const int num_new_edges = split_faces_prepare_new_edges(mesh, &new_edges, memarena);
+ /* We can have to split a vertex without having to add a single new edge... */
+ const bool do_edges = (num_new_edges > 0);
+
+ /* Reallocate all vert and edge related data. */
+ mesh->totvert += num_new_verts;
+ CustomData_realloc(&mesh->vdata, mesh->totvert);
+ if (do_edges) {
+ mesh->totedge += num_new_edges;
+ CustomData_realloc(&mesh->edata, mesh->totedge);
+ }
+ /* Update pointers to a newly allocated memory. */
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ /* Perform actual split of vertices and edges. */
+ split_faces_split_new_verts(mesh, new_verts, num_new_verts);
+ if (do_edges) {
+ split_faces_split_new_edges(mesh, new_edges, num_new_edges);
+ }
+ }
+
+ /* Note: after this point mesh is expected to be valid again. */
+
+ /* CD_NORMAL is expected to be temporary only. */
+ if (free_loop_normals) {
+ CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
+ }
+
+ /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
+ BKE_lnor_spacearr_free(&lnors_spacearr);
+
+#ifdef VALIDATE_MESH
+ BKE_mesh_validate(mesh, true, true);
+#endif
+}
+
/* settings: 1 - preview, 2 - render */
Mesh *BKE_mesh_new_from_object(
Main *bmain, Scene *sce, Object *ob,
@@ -2213,7 +2394,9 @@ Mesh *BKE_mesh_new_from_object(
int uv_from_orco;
/* copies object and modifiers (but not the data) */
- Object *tmpobj = BKE_object_copy_ex(bmain, ob, true);
+ Object *tmpobj;
+ /* TODO: make it temp copy outside bmain! */
+ BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES, false);
tmpcu = (Curve *)tmpobj->data;
id_us_min(&tmpcu->id);
@@ -2253,7 +2436,7 @@ Mesh *BKE_mesh_new_from_object(
/* convert object type to mesh */
uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
- BKE_mesh_from_nurbs_displist(tmpobj, &dispbase, uv_from_orco);
+ BKE_mesh_from_nurbs_displist(tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2);
tmpmesh = tmpobj->data;
@@ -2289,7 +2472,7 @@ Mesh *BKE_mesh_new_from_object(
if (ob != basis_ob)
return NULL; /* only do basis metaball */
- tmpmesh = BKE_mesh_add(bmain, "Mesh");
+ tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
/* BKE_mesh_add gives us a user count we don't need */
id_us_min(&tmpmesh->id);
@@ -2344,8 +2527,13 @@ Mesh *BKE_mesh_new_from_object(
else
dm = mesh_create_derived_view(sce, ob, mask);
- tmpmesh = BKE_mesh_add(bmain, "Mesh");
+ tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
DM_to_mesh(dm, tmpmesh, ob, mask, true);
+
+ /* Copy autosmooth settings from original mesh. */
+ Mesh *me = (Mesh *)ob->data;
+ tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH);
+ tmpmesh->smoothresh = me->smoothresh;
}
/* BKE_mesh_add/copy gives us a user count we don't need */
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index a3fe73e4b11..b28ec7f4fff 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -225,7 +225,7 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx)
}
/* accumulate angle weighted face normal */
- /* inline version of #accumulate_vertex_normals_poly */
+ /* inline version of #accumulate_vertex_normals_poly_v3 */
{
const float *prev_edge = edgevecbuf[nverts - 1];
@@ -304,13 +304,13 @@ void BKE_mesh_calc_normals_poly(
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
- TIMEIT_START(BKE_mesh_calc_normals);
+ TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
#endif
BKE_mesh_calc_normals_poly(mesh->mvert, NULL, mesh->totvert,
mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
NULL, false);
#ifdef DEBUG_TIME
- TIMEIT_END(BKE_mesh_calc_normals);
+ TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
}
@@ -334,8 +334,9 @@ void BKE_mesh_calc_normals_tessface(
else
normal_tri_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co);
- accumulate_vertex_normals(tnorms[mf->v1], tnorms[mf->v2], tnorms[mf->v3], n4,
- f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, c4);
+ accumulate_vertex_normals_v3(
+ tnorms[mf->v1], tnorms[mf->v2], tnorms[mf->v3], n4,
+ f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, c4);
}
/* following Mesh convention; we use vertex coordinate itself for normal in this case */
@@ -379,7 +380,7 @@ void BKE_mesh_calc_normals_looptri(
f_no,
mverts[vtri[0]].co, mverts[vtri[1]].co, mverts[vtri[2]].co);
- accumulate_vertex_normals_tri(
+ accumulate_vertex_normals_tri_v3(
tnorms[vtri[0]], tnorms[vtri[1]], tnorms[vtri[2]],
f_no, mverts[vtri[0]].co, mverts[vtri[1]].co, mverts[vtri[2]].co);
}
@@ -630,7 +631,6 @@ typedef struct LoopSplitTaskDataCommon {
* Note we do not need to protect it, though, since two different tasks will *always* affect different
* elements in the arrays. */
MLoopNorSpaceArray *lnors_spacearr;
- BLI_bitmap *sharp_verts;
float (*loopnors)[3];
short (*clnors_data)[2];
@@ -643,11 +643,8 @@ typedef struct LoopSplitTaskDataCommon {
const int *loop_to_poly;
const float (*polynors)[3];
+ int numLoops;
int numPolys;
-
- /* ***** Workers communication. ***** */
- ThreadQueue *task_queue;
-
} LoopSplitTaskDataCommon;
#define INDEX_UNSET INT_MIN
@@ -655,6 +652,50 @@ typedef struct LoopSplitTaskDataCommon {
/* See comment about edge_to_loops below. */
#define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID))
+static void loop_manifold_fan_around_vert_next(
+ const MLoop *mloops, const MPoly *mpolys,
+ const int *loop_to_poly, const int *e2lfan_curr, const uint mv_pivot_index,
+ const MLoop **r_mlfan_curr, int *r_mlfan_curr_index, int *r_mlfan_vert_index, int *r_mpfan_curr_index)
+{
+ const MLoop *mlfan_next;
+ const MPoly *mpfan_next;
+
+ /* Warning! This is rather complex!
+ * We have to find our next edge around the vertex (fan mode).
+ * First we find the next loop, which is either previous or next to mlfan_curr_index, depending
+ * whether both loops using current edge are in the same direction or not, and whether
+ * mlfan_curr_index actually uses the vertex we are fanning around!
+ * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
+ * (i.e. not the future mlfan_curr)...
+ */
+ *r_mlfan_curr_index = (e2lfan_curr[0] == *r_mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
+ *r_mpfan_curr_index = loop_to_poly[*r_mlfan_curr_index];
+
+ BLI_assert(*r_mlfan_curr_index >= 0);
+ BLI_assert(*r_mpfan_curr_index >= 0);
+
+ mlfan_next = &mloops[*r_mlfan_curr_index];
+ mpfan_next = &mpolys[*r_mpfan_curr_index];
+ if (((*r_mlfan_curr)->v == mlfan_next->v && (*r_mlfan_curr)->v == mv_pivot_index) ||
+ ((*r_mlfan_curr)->v != mlfan_next->v && (*r_mlfan_curr)->v != mv_pivot_index))
+ {
+ /* We need the previous loop, but current one is our vertex's loop. */
+ *r_mlfan_vert_index = *r_mlfan_curr_index;
+ if (--(*r_mlfan_curr_index) < mpfan_next->loopstart) {
+ *r_mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1;
+ }
+ }
+ else {
+ /* We need the next loop, which is also our vertex's loop. */
+ if (++(*r_mlfan_curr_index) >= mpfan_next->loopstart + mpfan_next->totloop) {
+ *r_mlfan_curr_index = mpfan_next->loopstart;
+ }
+ *r_mlfan_vert_index = *r_mlfan_curr_index;
+ }
+ *r_mlfan_curr = &mloops[*r_mlfan_curr_index];
+ /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
+}
+
static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
@@ -680,7 +721,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 / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index); */
+// 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) {
@@ -747,8 +788,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
const MEdge *me_org = &medges[ml_curr->e]; /* ml_curr would be mlfan_prev if we needed that one */
const int *e2lfan_curr;
float vec_curr[3], vec_prev[3], vec_org[3];
- const MLoop *mlfan_curr, *mlfan_next;
- const MPoly *mpfan_next;
+ const MLoop *mlfan_curr;
float lnor[3] = {0.0f, 0.0f, 0.0f};
/* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
@@ -787,7 +827,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
}
}
- /* printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e); */
+// printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e);
while (true) {
const MEdge *me_curr = &medges[mlfan_curr->e];
@@ -803,10 +843,10 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
normalize_v3(vec_curr);
}
- /* printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index); */
+// printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index);
{
- /* Code similar to accumulate_vertex_normals_poly. */
+ /* Code similar to accumulate_vertex_normals_poly_v3. */
/* Calculate angle between the two poly edges incident on this vertex. */
const float fac = saacos(dot_v3v3(vec_curr, vec_prev));
/* Accumulate */
@@ -845,46 +885,16 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
/* Current edge is sharp and we have finished with this fan of faces around this vert,
* or this vert is smooth, and we have completed a full turn around it.
*/
- /* printf("FAN: Finished!\n"); */
+// printf("FAN: Finished!\n");
break;
}
copy_v3_v3(vec_prev, vec_curr);
- /* Warning! This is rather complex!
- * We have to find our next edge around the vertex (fan mode).
- * First we find the next loop, which is either previous or next to mlfan_curr_index, depending
- * whether both loops using current edge are in the same direction or not, and whether
- * mlfan_curr_index actually uses the vertex we are fanning around!
- * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
- * (i.e. not the future mlfan_curr)...
- */
- mlfan_curr_index = (e2lfan_curr[0] == mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
- mpfan_curr_index = loop_to_poly[mlfan_curr_index];
-
- BLI_assert(mlfan_curr_index >= 0);
- BLI_assert(mpfan_curr_index >= 0);
-
- mlfan_next = &mloops[mlfan_curr_index];
- mpfan_next = &mpolys[mpfan_curr_index];
- if ((mlfan_curr->v == mlfan_next->v && mlfan_curr->v == mv_pivot_index) ||
- (mlfan_curr->v != mlfan_next->v && mlfan_curr->v != mv_pivot_index))
- {
- /* We need the previous loop, but current one is our vertex's loop. */
- mlfan_vert_index = mlfan_curr_index;
- if (--mlfan_curr_index < mpfan_next->loopstart) {
- mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1;
- }
- }
- else {
- /* We need the next loop, which is also our vertex's loop. */
- if (++mlfan_curr_index >= mpfan_next->loopstart + mpfan_next->totloop) {
- mlfan_curr_index = mpfan_next->loopstart;
- }
- mlfan_vert_index = mlfan_curr_index;
- }
- mlfan_curr = &mloops[mlfan_curr_index];
- /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
+ /* Find next loop of the smooth fan. */
+ loop_manifold_fan_around_vert_next(
+ mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index,
+ &mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index);
e2lfan_curr = edge_to_loops[mlfan_curr->e];
}
@@ -955,31 +965,25 @@ static void loop_split_worker_do(
}
}
-static void loop_split_worker(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void loop_split_worker(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
{
- LoopSplitTaskDataCommon *common_data = taskdata;
- LoopSplitTaskData *data_buff;
+ LoopSplitTaskDataCommon *common_data = BLI_task_pool_userdata(pool);
+ LoopSplitTaskData *data = taskdata;
/* Temp edge vectors stack, only used when computing lnor spacearr. */
BLI_Stack *edge_vectors = common_data->lnors_spacearr ? BLI_stack_new(sizeof(float[3]), __func__) : NULL;
#ifdef DEBUG_TIME
- TIMEIT_START(loop_split_worker);
+ TIMEIT_START_AVERAGED(loop_split_worker);
#endif
- while ((data_buff = BLI_thread_queue_pop(common_data->task_queue))) {
- LoopSplitTaskData *data = data_buff;
- int i;
-
- for (i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
- /* A NULL ml_curr is used to tag ended data! */
- if (data->ml_curr == NULL) {
- break;
- }
- loop_split_worker_do(common_data, data, edge_vectors);
+ for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
+ /* A NULL ml_curr is used to tag ended data! */
+ if (data->ml_curr == NULL) {
+ break;
}
- MEM_freeN(data_buff);
+ loop_split_worker_do(common_data, data, edge_vectors);
}
if (edge_vectors) {
@@ -987,49 +991,117 @@ static void loop_split_worker(TaskPool * __restrict UNUSED(pool), void *taskdata
}
#ifdef DEBUG_TIME
- TIMEIT_END(loop_split_worker);
+ TIMEIT_END_AVERAGED(loop_split_worker);
#endif
}
-/* Note we use data_buff to detect whether we are in threaded context or not, in later case it is NULL. */
-static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const bool threaded)
+/* Check whether gievn loop is part of an unknown-so-far cyclic smooth fan, or not.
+ * Needed because cyclic smooth fans have no obvious 'entry point', and yet we need to walk them once, and only once. */
+static bool loop_split_generator_check_cyclic_smooth_fan(
+ const MLoop *mloops, const MPoly *mpolys,
+ const int (*edge_to_loops)[2], const int *loop_to_poly, const int *e2l_prev, BLI_bitmap *skip_loops,
+ const MLoop *ml_curr, const MLoop *ml_prev, const int ml_curr_index, const int ml_prev_index,
+ const int mp_curr_index)
+{
+ const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const int *e2lfan_curr;
+ const MLoop *mlfan_curr;
+ /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
+ int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
+
+ e2lfan_curr = e2l_prev;
+ if (IS_EDGE_SHARP(e2lfan_curr)) {
+ /* Sharp loop, so not a cyclic smooth fan... */
+ return false;
+ }
+
+ mlfan_curr = ml_prev;
+ mlfan_curr_index = ml_prev_index;
+ mlfan_vert_index = ml_curr_index;
+ mpfan_curr_index = mp_curr_index;
+
+ BLI_assert(mlfan_curr_index >= 0);
+ BLI_assert(mlfan_vert_index >= 0);
+ BLI_assert(mpfan_curr_index >= 0);
+
+ BLI_assert(!BLI_BITMAP_TEST(skip_loops, mlfan_vert_index));
+ BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
+
+ while (true) {
+ /* Find next loop of the smooth fan. */
+ loop_manifold_fan_around_vert_next(
+ mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index,
+ &mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index);
+
+ e2lfan_curr = edge_to_loops[mlfan_curr->e];
+
+ if (IS_EDGE_SHARP(e2lfan_curr)) {
+ /* Sharp loop/edge, so not a cyclic smooth fan... */
+ return false;
+ }
+ /* Smooth loop/edge... */
+ else if (BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)) {
+ if (mlfan_vert_index == ml_curr_index) {
+ /* We walked around a whole cyclic smooth fan without finding any already-processed loop, means we can
+ * use initial ml_curr/ml_prev edge as start for this smooth fan. */
+ return true;
+ }
+ /* ... already checked in some previous looping, we can abort. */
+ return false;
+ }
+ else {
+ /* ... we can skip it in future, and keep checking the smooth fan. */
+ BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
+ }
+ }
+}
+
+static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- BLI_bitmap *sharp_verts = common_data->sharp_verts;
float (*loopnors)[3] = common_data->loopnors;
const MLoop *mloops = common_data->mloops;
const MPoly *mpolys = common_data->mpolys;
+ const int *loop_to_poly = common_data->loop_to_poly;
const int (*edge_to_loops)[2] = common_data->edge_to_loops;
+ const int numLoops = common_data->numLoops;
const int numPolys = common_data->numPolys;
const MPoly *mp;
int mp_index;
- LoopSplitTaskData *data, *data_buff = NULL, data_mem;
+ const MLoop *ml_curr;
+ const MLoop *ml_prev;
+ int ml_curr_index;
+ int ml_prev_index;
+
+ BLI_bitmap *skip_loops = BLI_BITMAP_NEW(numLoops, __func__);
+
+ LoopSplitTaskData *data_buff = NULL;
int data_idx = 0;
/* Temp edge vectors stack, only used when computing lnor spacearr (and we are not multi-threading). */
- BLI_Stack *edge_vectors = (lnors_spacearr && !data_buff) ? BLI_stack_new(sizeof(float[3]), __func__) : NULL;
+ BLI_Stack *edge_vectors = NULL;
#ifdef DEBUG_TIME
- TIMEIT_START(loop_split_generator);
+ TIMEIT_START_AVERAGED(loop_split_generator);
#endif
- if (!threaded) {
- memset(&data_mem, 0, sizeof(data_mem));
- data = &data_mem;
+ if (!pool) {
+ if (lnors_spacearr) {
+ edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
+ }
}
/* We now know edges that can be smoothed (with their vector, and their two loops), and edges that will be hard!
* Now, time to generate the normals.
*/
for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- const MLoop *ml_curr, *ml_prev;
float (*lnors)[3];
const int ml_last_index = (mp->loopstart + mp->totloop) - 1;
- int ml_curr_index = mp->loopstart;
- int ml_prev_index = ml_last_index;
+ ml_curr_index = mp->loopstart;
+ ml_prev_index = ml_last_index;
ml_curr = &mloops[ml_curr_index];
ml_prev = &mloops[ml_prev_index];
@@ -1039,23 +1111,40 @@ static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const
const int *e2l_curr = edge_to_loops[ml_curr->e];
const int *e2l_prev = edge_to_loops[ml_prev->e];
- if (!IS_EDGE_SHARP(e2l_curr) && (!lnors_spacearr || BLI_BITMAP_TEST_BOOL(sharp_verts, ml_curr->v))) {
- /* A smooth edge, and we are not generating lnor_spacearr, or the related vertex is sharp.
- * We skip it because it is either:
- * - in the middle of a 'smooth fan' already computed (or that will be as soon as we hit
- * one of its ends, i.e. one of its two sharp edges), or...
- * - the related vertex is a "full smooth" one, in which case pre-populated normals from vertex
- * are just fine (or it has already be handled in a previous loop in case of needed lnors spacearr)!
- */
- /* printf("Skipping loop %d / edge %d / vert %d(%d)\n", ml_curr_index, ml_curr->e, ml_curr->v, sharp_verts[ml_curr->v]); */
+// printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)...",
+// ml_curr_index, ml_curr->e, ml_curr->v, IS_EDGE_SHARP(e2l_curr), BLI_BITMAP_TEST_BOOL(skip_loops, ml_curr_index));
+
+ /* A smooth edge, we have to check for cyclic smooth fan case.
+ * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as
+ * 'entry point', otherwise we can skip it. */
+ /* Note: In theory, we could make loop_split_generator_check_cyclic_smooth_fan() store
+ * mlfan_vert_index'es and edge indexes in two stacks, to avoid having to fan again around the vert during
+ * actual computation of clnor & clnorspace. However, this would complicate the code, add more memory usage,
+ * and despite its logical complexity, loop_manifold_fan_around_vert_next() is quite cheap in term of
+ * CPU cycles, so really think it's not worth it. */
+ if (!IS_EDGE_SHARP(e2l_curr) &&
+ (BLI_BITMAP_TEST(skip_loops, ml_curr_index) ||
+ !loop_split_generator_check_cyclic_smooth_fan(
+ mloops, mpolys, edge_to_loops, loop_to_poly, e2l_prev, skip_loops,
+ ml_curr, ml_prev, ml_curr_index, ml_prev_index, mp_index)))
+ {
+// printf("SKIPPING!\n");
}
else {
- if (threaded) {
+ LoopSplitTaskData *data, data_local;
+
+// printf("PROCESSING!\n");
+
+ if (pool) {
if (data_idx == 0) {
data_buff = MEM_callocN(sizeof(*data_buff) * LOOP_SPLIT_TASK_BLOCK_SIZE, __func__);
}
data = &data_buff[data_idx];
}
+ else {
+ data = &data_local;
+ memset(data, 0, sizeof(*data));
+ }
if (IS_EDGE_SHARP(e2l_curr) && IS_EDGE_SHARP(e2l_prev)) {
data->lnor = lnors;
@@ -1091,22 +1180,18 @@ static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const
data->mp_index = mp_index;
if (lnors_spacearr) {
data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
- /* Tag related vertex as sharp, to avoid fanning around it again (in case it was a smooth one).
- * This *has* to be done outside of workers tasks! */
- BLI_BITMAP_ENABLE(sharp_verts, ml_curr->v);
}
}
- if (threaded) {
+ if (pool) {
data_idx++;
if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
- BLI_thread_queue_push(common_data->task_queue, data_buff);
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
data_idx = 0;
}
}
else {
loop_split_worker_do(common_data, data, edge_vectors);
- memset(data, 0, sizeof(data_mem));
}
}
@@ -1115,44 +1200,32 @@ static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const
}
}
- if (threaded) {
- /* Last block of data... Since it is calloc'ed and we use first NULL item as stopper, everything is fine. */
- if (LIKELY(data_idx)) {
- BLI_thread_queue_push(common_data->task_queue, data_buff);
- }
-
- /* This will signal all other worker threads to wake up and finish! */
- BLI_thread_queue_nowait(common_data->task_queue);
+ /* Last block of data... Since it is calloc'ed and we use first NULL item as stopper, everything is fine. */
+ if (pool && data_idx) {
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
}
if (edge_vectors) {
BLI_stack_free(edge_vectors);
}
+ MEM_freeN(skip_loops);
#ifdef DEBUG_TIME
- TIMEIT_END(loop_split_generator);
+ TIMEIT_END_AVERAGED(loop_split_generator);
#endif
}
-static void loop_split_generator(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
-{
- LoopSplitTaskDataCommon *common_data = taskdata;
-
- loop_split_generator_do(common_data, true);
-}
-
/**
* Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
*/
void BKE_mesh_normals_loop_split(
- const MVert *mverts, const int numVerts, MEdge *medges, const int numEdges,
+ const MVert *mverts, const int UNUSED(numVerts), MEdge *medges, const int numEdges,
MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
MPoly *mpolys, const float (*polynors)[3], const int numPolys,
const bool use_split_normals, float split_angle,
MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], int *r_loop_to_poly)
{
-
/* For now this is not supported. If we do not use split normals, we do not generate anything fancy! */
BLI_assert(use_split_normals || !(r_lnors_spacearr));
@@ -1185,8 +1258,6 @@ void BKE_mesh_normals_loop_split(
return;
}
- {
-
/* Mapping edge -> loops.
* If that edge is used by more than two loops (polys), it is always sharp (and tagged as such, see below).
* We also use the second loop index as a kind of flag: smooth edge: > 0,
@@ -1196,33 +1267,25 @@ void BKE_mesh_normals_loop_split(
* store the negated value of loop index instead of INDEX_INVALID to retrieve the real value later in code).
* Note also that lose edges always have both values set to 0!
*/
- int (*edge_to_loops)[2] = MEM_callocN(sizeof(int[2]) * (size_t)numEdges, __func__);
+ int (*edge_to_loops)[2] = MEM_callocN(sizeof(*edge_to_loops) * (size_t)numEdges, __func__);
/* Simple mapping from a loop to its polygon index. */
- int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_mallocN(sizeof(int) * (size_t)numLoops, __func__);
+ int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_mallocN(sizeof(*loop_to_poly) * (size_t)numLoops, __func__);
MPoly *mp;
- int mp_index, me_index;
- bool check_angle = (split_angle < (float)M_PI);
- int i;
+ int mp_index;
- BLI_bitmap *sharp_verts = NULL;
- MLoopNorSpaceArray _lnors_spacearr = {NULL};
+ /* When using custom loop normals, disable the angle feature! */
+ const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == NULL);
- LoopSplitTaskDataCommon common_data = {NULL};
+ MLoopNorSpaceArray _lnors_spacearr = {NULL};
#ifdef DEBUG_TIME
- TIMEIT_START(BKE_mesh_normals_loop_split);
+ TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split);
#endif
if (check_angle) {
- /* When using custom loop normals, disable the angle feature! */
- if (clnors_data) {
- check_angle = false;
- }
- else {
- split_angle = cosf(split_angle);
- }
+ split_angle = cosf(split_angle);
}
if (!r_lnors_spacearr && clnors_data) {
@@ -1231,7 +1294,6 @@ void BKE_mesh_normals_loop_split(
}
if (r_lnors_spacearr) {
BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops);
- sharp_verts = BLI_BITMAP_NEW((size_t)numVerts, __func__);
}
/* This first loop check which edges are actually smooth, and compute edge vectors. */
@@ -1285,60 +1347,38 @@ void BKE_mesh_normals_loop_split(
}
}
- if (r_lnors_spacearr) {
- /* Tag vertices that have at least one sharp edge as 'sharp' (used for the lnor spacearr computation).
- * XXX This third loop over edges is a bit disappointing, could not find any other way yet.
- * Not really performance-critical anyway.
- */
- for (me_index = 0; me_index < numEdges; me_index++) {
- const int *e2l = edge_to_loops[me_index];
- const MEdge *me = &medges[me_index];
- if (IS_EDGE_SHARP(e2l)) {
- BLI_BITMAP_ENABLE(sharp_verts, me->v1);
- BLI_BITMAP_ENABLE(sharp_verts, me->v2);
- }
- }
- }
-
/* Init data common to all tasks. */
- common_data.lnors_spacearr = r_lnors_spacearr;
- common_data.loopnors = r_loopnors;
- common_data.clnors_data = clnors_data;
-
- common_data.mverts = mverts;
- common_data.medges = medges;
- common_data.mloops = mloops;
- common_data.mpolys = mpolys;
- common_data.sharp_verts = sharp_verts;
- common_data.edge_to_loops = (const int(*)[2])edge_to_loops;
- common_data.loop_to_poly = loop_to_poly;
- common_data.polynors = polynors;
- common_data.numPolys = numPolys;
+ LoopSplitTaskDataCommon common_data = {
+ .lnors_spacearr = r_lnors_spacearr,
+ .loopnors = r_loopnors,
+ .clnors_data = clnors_data,
+ .mverts = mverts,
+ .medges = medges,
+ .mloops = mloops,
+ .mpolys = mpolys,
+ .edge_to_loops = (const int(*)[2])edge_to_loops,
+ .loop_to_poly = loop_to_poly,
+ .polynors = polynors,
+ .numLoops = numLoops,
+ .numPolys = numPolys,
+ };
if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
/* Not enough loops to be worth the whole threading overhead... */
- loop_split_generator_do(&common_data, false);
+ loop_split_generator(NULL, &common_data);
}
else {
TaskScheduler *task_scheduler;
TaskPool *task_pool;
- int nbr_workers;
-
- common_data.task_queue = BLI_thread_queue_init();
task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, NULL);
+ task_pool = BLI_task_pool_create(task_scheduler, &common_data);
+
+ loop_split_generator(task_pool, &common_data);
- nbr_workers = max_ii(2, BLI_task_scheduler_num_threads(task_scheduler));
- for (i = 1; i < nbr_workers; i++) {
- BLI_task_pool_push(task_pool, loop_split_worker, &common_data, false, TASK_PRIORITY_HIGH);
- }
- BLI_task_pool_push(task_pool, loop_split_generator, &common_data, false, TASK_PRIORITY_HIGH);
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
-
- BLI_thread_queue_free(common_data.task_queue);
}
MEM_freeN(edge_to_loops);
@@ -1347,17 +1387,14 @@ void BKE_mesh_normals_loop_split(
}
if (r_lnors_spacearr) {
- MEM_freeN(sharp_verts);
if (r_lnors_spacearr == &_lnors_spacearr) {
BKE_lnor_spacearr_free(r_lnors_spacearr);
}
}
#ifdef DEBUG_TIME
- TIMEIT_END(BKE_mesh_normals_loop_split);
+ TIMEIT_END_AVERAGED(BKE_mesh_normals_loop_split);
#endif
-
- }
}
#undef INDEX_UNSET
@@ -1593,8 +1630,8 @@ void BKE_mesh_normals_loop_custom_from_vertices_set(
/**
* Computes average per-vertex normals from given custom loop normals.
*
- * @param clnors The computed custom loop normals.
- * @param r_vert_clnors The (already allocated) array where to store averaged per-vertex normals.
+ * \param clnors: The computed custom loop normals.
+ * \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals.
*/
void BKE_mesh_normals_loop_to_vertex(
const int numVerts, const MLoop *mloops, const int numLoops,
@@ -1909,19 +1946,19 @@ void BKE_mesh_calc_poly_center(
const MVert *mvarray, float r_cent[3])
{
if (mpoly->totloop == 3) {
- cent_tri_v3(r_cent,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co
- );
+ mid_v3_v3v3v3(r_cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co
+ );
}
else if (mpoly->totloop == 4) {
- cent_quad_v3(r_cent,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co,
- mvarray[loopstart[3].v].co
- );
+ mid_v3_v3v3v3v3(r_cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co,
+ mvarray[loopstart[3].v].co
+ );
}
else {
mesh_calc_ngon_center(mpoly, loopstart, mvarray, r_cent);
@@ -1957,8 +1994,66 @@ float BKE_mesh_calc_poly_area(
}
}
-/* note, results won't be correct if polygon is non-planar */
-static float mesh_calc_poly_planar_area_centroid(
+/**
+ * Calculate the volume and volume-weighted centroid of the volume formed by the polygon and the origin.
+ * Results will be negative if the origin is "outside" the polygon
+ * (+ve normal side), but the polygon may be non-planar with no effect.
+ *
+ * Method from:
+ * - http://forums.cgsociety.org/archive/index.php?t-756235.html
+ * - http://www.globalspec.com/reference/52702/203279/4-8-the-centroid-of-a-tetrahedron
+ *
+ * \note
+ * - Volume is 6x actual volume, and centroid is 4x actual volume-weighted centroid
+ * (so division can be done once at the end).
+ * - Results will have bias if polygon is non-planar.
+ * - The resulting volume will only be correct if the mesh is manifold and has consistent face winding
+ * (non-contiguous face normals or holes in the mesh surface).
+ */
+static float mesh_calc_poly_volume_centroid(
+ const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray,
+ float r_cent[3])
+{
+ const float *v_pivot, *v_step1;
+ float total_volume = 0.0f;
+
+ zero_v3(r_cent);
+
+ v_pivot = mvarray[loopstart[0].v].co;
+ v_step1 = mvarray[loopstart[1].v].co;
+
+ for (int i = 2; i < mpoly->totloop; i++) {
+ const float *v_step2 = mvarray[loopstart[i].v].co;
+
+ /* Calculate the 6x volume of the tetrahedron formed by the 3 vertices
+ * of the triangle and the origin as the fourth vertex */
+ float v_cross[3];
+ cross_v3_v3v3(v_cross, v_pivot, v_step1);
+ const float tetra_volume = dot_v3v3 (v_cross, v_step2);
+ total_volume += tetra_volume;
+
+ /* Calculate the centroid of the tetrahedron formed by the 3 vertices
+ * of the triangle and the origin as the fourth vertex.
+ * The centroid is simply the average of the 4 vertices.
+ *
+ * Note that the vector is 4x the actual centroid so the division can be done once at the end. */
+ for (uint j = 0; j < 3; j++) {
+ r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]);
+ }
+
+ v_step1 = v_step2;
+ }
+
+ return total_volume;
+}
+
+/**
+ * \note
+ * - Results won't be correct if polygon is non-planar.
+ * - This has the advantage over #mesh_calc_poly_volume_centroid
+ * that it doesn't depend on solid geometry, instead it weights the surface by volume.
+ */
+static float mesh_calc_poly_area_centroid(
const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray,
float r_cent[3])
{
@@ -1978,7 +2073,7 @@ static float mesh_calc_poly_planar_area_centroid(
tri_area = area_tri_signed_v3(v1, v2, v3, normal);
total_area += tri_area;
- cent_tri_v3(tri_cent, v1, v2, v3);
+ mid_v3_v3v3v3(tri_cent, v1, v2, v3);
madd_v3_v3fl(r_cent, tri_cent, tri_area);
copy_v3_v3(v2, v3);
@@ -2103,7 +2198,7 @@ bool BKE_mesh_center_bounds(const Mesh *me, float r_cent[3])
return false;
}
-bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3])
+bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3])
{
int i = me->totpoly;
MPoly *mpoly;
@@ -2115,7 +2210,7 @@ bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3])
/* calculate a weighted average of polygon centroids */
for (mpoly = me->mpoly; i--; mpoly++) {
- poly_area = mesh_calc_poly_planar_area_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
+ poly_area = mesh_calc_poly_area_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
madd_v3_v3fl(r_cent, poly_cent, poly_area);
total_area += poly_area;
@@ -2132,6 +2227,43 @@ bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3])
return (me->totpoly != 0);
}
+
+/**
+ * \note Mesh must be manifold with consistent face-winding, see #mesh_calc_poly_volume_centroid for details.
+ */
+bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3])
+{
+ int i = me->totpoly;
+ MPoly *mpoly;
+ float poly_volume;
+ float total_volume = 0.0f;
+ float poly_cent[3];
+
+ zero_v3(r_cent);
+
+ /* calculate a weighted average of polyhedron centroids */
+ for (mpoly = me->mpoly; i--; mpoly++) {
+ poly_volume = mesh_calc_poly_volume_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
+
+ /* poly_cent is already volume-weighted, so no need to multiply by the volume */
+ add_v3_v3(r_cent, poly_cent);
+ total_volume += poly_volume;
+ }
+ /* otherwise we get NAN for 0 polys */
+ if (total_volume != 0.0f) {
+ /* multipy by 0.25 to get the correct centroid */
+ /* no need to divide volume by 6 as the centroid is weighted by 6x the volume, so it all cancels out */
+ mul_v3_fl(r_cent, 0.25f / total_volume);
+ }
+
+ /* this can happen for non-manifold objects, fallback to median */
+ if (UNLIKELY(!is_finite_v3(r_cent))) {
+ return BKE_mesh_center_median(me, r_cent);
+ }
+
+ return (me->totpoly != 0);
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index 8562988b5e1..525c0c9728e 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -165,7 +165,7 @@ UvVertMap *BKE_mesh_uv_vert_map_create(
vmap->vert[a] = newvlist;
}
- if (use_winding) {
+ if (use_winding) {
MEM_freeN(winding);
}
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index c5fa9b15896..d2fe8f27f4a 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -1184,7 +1184,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
bool polys_allocated_src;
MPoly *polys_src = DM_get_poly_array(dm_src, &polys_allocated_src);
const int num_polys_src = dm_src->getNumPolys(dm_src);
- bool looptri_allocated_src = false;
const MLoopTri *looptri_src = NULL;
int num_looptri_src = 0;
@@ -1374,17 +1373,11 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (dirty_tess_flag) {
dm_src->dirty &= ~dirty_tess_flag;
}
- DM_ensure_looptri(dm_src);
if (dirty_tess_flag) {
dm_src->dirty |= dirty_tess_flag;
}
- looptri_src = DM_get_looptri_array(
- dm_src,
- verts_src,
- polys_src, num_polys_src,
- loops_src, num_loops_src,
- &looptri_allocated_src);
+ looptri_src = dm_src->getLoopTriArray(dm_src);
num_looptri_src = dm_src->getNumLoopTri(dm_src);
looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__);
@@ -1403,7 +1396,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
&treedata[tindex],
verts_src, verts_allocated_src,
loops_src, loops_allocated_src,
- looptri_src, num_looptri_src, looptri_allocated_src,
+ looptri_src, num_looptri_src, false,
looptri_active, num_looptri_active, bvh_epsilon, 2, 6);
if (verts_allocated_src) {
verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */
@@ -1411,9 +1404,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (loops_allocated_src) {
loops_allocated_src = false; /* Only 'give' our loops once, to first tree! */
}
- if (looptri_allocated_src) {
- looptri_allocated_src = false; /* Only 'give' our looptri once, to first tree! */
- }
}
MEM_freeN(looptri_active);
@@ -1928,9 +1918,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (polys_allocated_src) {
MEM_freeN(polys_src);
}
- if (looptri_allocated_src) {
- MEM_freeN((void *)looptri_src);
- }
if (vert_to_loop_map_src) {
MEM_freeN(vert_to_loop_map_src);
}
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index ba890b005d8..4aeddbb4c45 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -584,8 +584,8 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
int prev_e = ml->e;
ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
fix_flag.loops_edge = true;
- PRINT_ERR("\tPoly %u has invalid edge reference (%d), fixed using edge %u\n",
- sp->index, prev_e, ml->e);
+ PRINT_ERR("\tPoly %u has invalid edge reference (%d, is_removed: %d), fixed using edge %u\n",
+ sp->index, prev_e, IS_REMOVED_EDGE(me), ml->e);
}
else {
PRINT_ERR("\tPoly %u has invalid edge reference (%u)\n", sp->index, ml->e);
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 41e4c21d814..118bafa94d2 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -49,15 +49,18 @@
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
#include "BLI_listbase.h"
#include "BLI_linklist.h"
+#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
#include "BKE_appdir.h"
#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_multires.h"
#include "BKE_DerivedMesh.h"
@@ -268,14 +271,37 @@ void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst)
memcpy(md_dst_data, md_src_data, (size_t)mti->structSize - data_size);
}
-void modifier_copyData(ModifierData *md, ModifierData *target)
+static void modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
+}
+
+void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
target->mode = md->mode;
- if (mti->copyData)
+ if (mti->copyData) {
mti->copyData(md, target);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(target, NULL, modifier_copy_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(target, NULL, (ObjectWalkFunc)modifier_copy_data_id_us_cb, NULL);
+ }
+ }
+}
+
+void modifier_copyData(ModifierData *md, ModifierData *target)
+{
+ modifier_copyData_ex(md, target, 0);
}
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 6794a8e8f93..16d597e25fa 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -588,7 +588,7 @@ static MovieClip *movieclip_alloc(Main *bmain, const char *name)
{
MovieClip *clip;
- clip = BKE_libblock_alloc(bmain, ID_MC, name);
+ clip = BKE_libblock_alloc(bmain, ID_MC, name, 0);
clip->aspx = clip->aspy = 1.0f;
@@ -1488,25 +1488,33 @@ void BKE_movieclip_free(MovieClip *clip)
BKE_animdata_free((ID *) clip, false);
}
-MovieClip *BKE_movieclip_copy(Main *bmain, MovieClip *clip)
+/**
+ * Only copy internal data of MovieClip ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_movieclip_copy_data(Main *UNUSED(bmain), MovieClip *clip_dst, const MovieClip *clip_src, const int flag)
{
- MovieClip *clip_new;
-
- clip_new = BKE_libblock_copy(bmain, &clip->id);
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
- clip_new->anim = NULL;
- clip_new->cache = NULL;
+ clip_dst->anim = NULL;
+ clip_dst->cache = NULL;
- BKE_tracking_copy(&clip_new->tracking, &clip->tracking);
- clip_new->tracking_context = NULL;
+ BKE_tracking_copy(&clip_dst->tracking, &clip_src->tracking, flag_subdata);
+ clip_dst->tracking_context = NULL;
- id_us_plus((ID *)clip_new->gpd);
-
- BKE_color_managed_colorspace_settings_copy(&clip_new->colorspace_settings, &clip->colorspace_settings);
-
- BKE_id_copy_ensure_local(bmain, &clip->id, &clip_new->id);
+ BKE_color_managed_colorspace_settings_copy(&clip_dst->colorspace_settings, &clip_src->colorspace_settings);
+}
- return clip_new;
+MovieClip *BKE_movieclip_copy(Main *bmain, const MovieClip *clip)
+{
+ MovieClip *clip_copy;
+ BKE_id_copy_ex(bmain, &clip->id, (ID **)&clip_copy, 0, false);
+ return clip_copy;
}
void BKE_movieclip_make_local(Main *bmain, MovieClip *clip, const bool lib_local)
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index c321bc92a71..148fc3827e0 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -40,9 +40,9 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_ghash.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index a227228ceb5..54afe76ec07 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -46,10 +46,11 @@
#include "DNA_world_types.h"
#include "DNA_linestyle_types.h"
-#include "BLI_string.h"
-#include "BLI_math.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -901,80 +902,100 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type)
return nodeAddNode(C, ntree, idname);
}
-static void node_socket_copy(bNodeSocket *dst, bNodeSocket *src)
+static void node_socket_copy(bNodeSocket *sock_dst, bNodeSocket *sock_src, const int flag)
{
- src->new_sock = dst;
-
- if (src->prop)
- dst->prop = IDP_CopyProperty(src->prop);
-
- if (src->default_value)
- dst->default_value = MEM_dupallocN(src->default_value);
-
- dst->stack_index = 0;
+ sock_src->new_sock = sock_dst;
+
+ if (sock_src->prop) {
+ sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag);
+ }
+
+ if (sock_src->default_value) {
+ sock_dst->default_value = MEM_dupallocN(sock_src->default_value);
+ }
+
+ sock_dst->stack_index = 0;
/* XXX some compositor node (e.g. image, render layers) still store
* some persistent buffer data here, need to clear this to avoid dangling pointers.
*/
- dst->cache = NULL;
+ sock_dst->cache = NULL;
}
/* keep socket listorder identical, for copying links */
/* ntree is the target tree */
-bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
+bNode *BKE_node_copy_ex(bNodeTree *ntree, bNode *node_src, const int flag)
{
- bNode *nnode = MEM_callocN(sizeof(bNode), "dupli node");
- bNodeSocket *sock, *oldsock;
- bNodeLink *link, *oldlink;
+ bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node");
+ bNodeSocket *sock_dst, *sock_src;
+ bNodeLink *link_dst, *link_src;
- *nnode = *node;
+ *node_dst = *node_src;
/* can be called for nodes outside a node tree (e.g. clipboard) */
if (ntree) {
- nodeUniqueName(ntree, nnode);
+ nodeUniqueName(ntree, node_dst);
- BLI_addtail(&ntree->nodes, nnode);
+ BLI_addtail(&ntree->nodes, node_dst);
}
- BLI_duplicatelist(&nnode->inputs, &node->inputs);
- oldsock = node->inputs.first;
- for (sock = nnode->inputs.first; sock; sock = sock->next, oldsock = oldsock->next)
- node_socket_copy(sock, oldsock);
-
- BLI_duplicatelist(&nnode->outputs, &node->outputs);
- oldsock = node->outputs.first;
- for (sock = nnode->outputs.first; sock; sock = sock->next, oldsock = oldsock->next)
- node_socket_copy(sock, oldsock);
-
- if (node->prop)
- nnode->prop = IDP_CopyProperty(node->prop);
-
- BLI_duplicatelist(&nnode->internal_links, &node->internal_links);
- oldlink = node->internal_links.first;
- for (link = nnode->internal_links.first; link; link = link->next, oldlink = oldlink->next) {
- link->fromnode = nnode;
- link->tonode = nnode;
- link->fromsock = link->fromsock->new_sock;
- link->tosock = link->tosock->new_sock;
+ BLI_duplicatelist(&node_dst->inputs, &node_src->inputs);
+ for (sock_dst = node_dst->inputs.first, sock_src = node_src->inputs.first;
+ sock_dst != NULL;
+ sock_dst = sock_dst->next, sock_src = sock_src->next)
+ {
+ node_socket_copy(sock_dst, sock_src, flag);
}
-
- /* don't increase node->id users, freenode doesn't decrement either */
-
- if (node->typeinfo->copyfunc)
- node->typeinfo->copyfunc(ntree, nnode, node);
-
- node->new_node = nnode;
- nnode->new_node = NULL;
-
- if (nnode->typeinfo->copyfunc_api) {
+
+ BLI_duplicatelist(&node_dst->outputs, &node_src->outputs);
+ for (sock_dst = node_dst->outputs.first, sock_src = node_src->outputs.first;
+ sock_dst != NULL;
+ sock_dst = sock_dst->next, sock_src = sock_src->next)
+ {
+ node_socket_copy(sock_dst, sock_src, flag);
+ }
+
+ if (node_src->prop) {
+ node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag);
+ }
+
+ BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links);
+ for (link_dst = node_dst->internal_links.first, link_src = node_src->internal_links.first;
+ link_dst != NULL;
+ link_dst = link_dst->next, link_src = link_src->next)
+ {
+ link_dst->fromnode = node_dst;
+ link_dst->tonode = node_dst;
+ link_dst->fromsock = link_dst->fromsock->new_sock;
+ link_dst->tosock = link_dst->tosock->new_sock;
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(node_dst->id);
+ }
+
+ if (node_src->typeinfo->copyfunc) {
+ node_src->typeinfo->copyfunc(ntree, node_dst, node_src);
+ }
+
+ node_src->new_node = node_dst;
+ node_dst->new_node = NULL;
+
+ if (node_dst->typeinfo->copyfunc_api) {
PointerRNA ptr;
- RNA_pointer_create((ID *)ntree, &RNA_Node, nnode, &ptr);
-
- nnode->typeinfo->copyfunc_api(&ptr, node);
+ RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr);
+
+ node_dst->typeinfo->copyfunc_api(&ptr, node_src);
}
-
- if (ntree)
+
+ if (ntree) {
ntree->update |= NTREE_UPDATE_NODES;
-
- return nnode;
+ }
+
+ return node_dst;
+}
+
+bNode *nodeCopyNode(bNodeTree *ntree, bNode *node)
+{
+ return BKE_node_copy_ex(ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT);
}
/* also used via rna api, so we check for proper input output direction */
@@ -1171,7 +1192,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
* node groups and other tree types are created as library data.
*/
if (bmain) {
- ntree = BKE_libblock_alloc(bmain, ID_NT, name);
+ ntree = BKE_libblock_alloc(bmain, ID_NT, name, 0);
}
else {
ntree = MEM_callocN(sizeof(bNodeTree), "new node tree");
@@ -1190,150 +1211,102 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
return ntree;
}
-/* Warning: this function gets called during some rather unexpected times
- * - this gets called when executing compositing updates (for threaded previews)
- * - when the nodetree datablock needs to be copied (i.e. when users get copied)
- * - for scene duplication use ntreeSwapID() after so we don't have stale pointers.
+/**
+ * Only copy internal data of NodeTree ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
*
- * do_make_extern: keep enabled for general use, only reason _not_ to enable is when
- * copying for internal use (threads for eg), where you wont want it to modify the
- * scene data.
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool skip_database, bool do_id_user, bool do_make_extern, bool copy_previews)
+void BKE_node_tree_copy_data(Main *UNUSED(bmain), bNodeTree *ntree_dst, const bNodeTree *ntree_src, const int flag)
{
- bNodeTree *newtree;
- bNode *node /*, *nnode */ /* UNUSED */, *last;
- bNodeSocket *sock, *oldsock;
- bNodeLink *link;
-
- if (ntree == NULL) return NULL;
-
- /* is ntree part of library? */
- if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) {
- newtree = BKE_libblock_copy(bmain, &ntree->id);
- }
- else {
- newtree = BKE_libblock_copy_nolib(&ntree->id, true);
- }
+ bNodeSocket *sock_dst, *sock_src;
+ bNodeLink *link_dst;
- id_us_plus((ID *)newtree->gpd);
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
/* in case a running nodetree is copied */
- newtree->execdata = NULL;
-
- newtree->duplilock = NULL;
-
- BLI_listbase_clear(&newtree->nodes);
- BLI_listbase_clear(&newtree->links);
-
- last = ntree->nodes.last;
- for (node = ntree->nodes.first; node; node = node->next) {
+ ntree_dst->execdata = NULL;
- /* ntreeUserDecrefID inline */
- if (do_id_user) {
- id_us_plus(node->id);
- }
+ ntree_dst->duplilock = NULL;
- if (do_make_extern) {
- id_lib_extern(node->id);
- }
+ BLI_listbase_clear(&ntree_dst->nodes);
+ BLI_listbase_clear(&ntree_dst->links);
- node->new_node = NULL;
- /* nnode = */ nodeCopyNode(newtree, node); /* sets node->new */
-
- /* make sure we don't copy new nodes again! */
- if (node == last)
- break;
+ for (bNode *node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) {
+ BKE_node_copy_ex(ntree_dst, node_src, flag_subdata);
}
-
+
/* copy links */
- BLI_duplicatelist(&newtree->links, &ntree->links);
- for (link = newtree->links.first; link; link = link->next) {
- link->fromnode = (link->fromnode ? link->fromnode->new_node : NULL);
- link->fromsock = (link->fromsock ? link->fromsock->new_sock : NULL);
- link->tonode = (link->tonode ? link->tonode->new_node : NULL);
- link->tosock = (link->tosock ? link->tosock->new_sock : NULL);
+ BLI_duplicatelist(&ntree_dst->links, &ntree_src->links);
+ for (link_dst = ntree_dst->links.first; link_dst; link_dst = link_dst->next) {
+ link_dst->fromnode = (link_dst->fromnode ? link_dst->fromnode->new_node : NULL);
+ link_dst->fromsock = (link_dst->fromsock ? link_dst->fromsock->new_sock : NULL);
+ link_dst->tonode = (link_dst->tonode ? link_dst->tonode->new_node : NULL);
+ link_dst->tosock = (link_dst->tosock ? link_dst->tosock->new_sock : NULL);
/* update the link socket's pointer */
- if (link->tosock)
- link->tosock->link = link;
+ if (link_dst->tosock) {
+ link_dst->tosock->link = link_dst;
+ }
}
-
+
/* copy interface sockets */
- BLI_duplicatelist(&newtree->inputs, &ntree->inputs);
- oldsock = ntree->inputs.first;
- for (sock = newtree->inputs.first; sock; sock = sock->next, oldsock = oldsock->next)
- node_socket_copy(sock, oldsock);
-
- BLI_duplicatelist(&newtree->outputs, &ntree->outputs);
- oldsock = ntree->outputs.first;
- for (sock = newtree->outputs.first; sock; sock = sock->next, oldsock = oldsock->next)
- node_socket_copy(sock, oldsock);
-
+ BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs);
+ for (sock_dst = ntree_dst->inputs.first, sock_src = ntree_src->inputs.first;
+ sock_dst != NULL;
+ sock_dst = sock_dst->next, sock_src = sock_src->next)
+ {
+ node_socket_copy(sock_dst, sock_src, flag_subdata);
+ }
+
+ BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs);
+ for (sock_dst = ntree_dst->outputs.first, sock_src = ntree_src->outputs.first;
+ sock_dst != NULL;
+ sock_dst = sock_dst->next, sock_src = sock_src->next)
+ {
+ node_socket_copy(sock_dst, sock_src, flag_subdata);
+ }
+
/* copy preview hash */
- if (ntree->previews && copy_previews) {
+ if (ntree_src->previews && (flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
bNodeInstanceHashIterator iter;
-
- newtree->previews = BKE_node_instance_hash_new("node previews");
-
- NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
+
+ ntree_dst->previews = BKE_node_instance_hash_new("node previews");
+
+ NODE_INSTANCE_HASH_ITER(iter, ntree_src->previews) {
bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
- BKE_node_instance_hash_insert(newtree->previews, key, BKE_node_preview_copy(preview));
+ BKE_node_instance_hash_insert(ntree_dst->previews, key, BKE_node_preview_copy(preview));
}
}
- else
- newtree->previews = NULL;
-
+ else {
+ ntree_dst->previews = NULL;
+ }
+
/* update node->parent pointers */
- for (node = newtree->nodes.first; node; node = node->next) {
- if (node->parent)
- node->parent = node->parent->new_node;
+ for (bNode *node_dst = ntree_dst->nodes.first, *node_src = ntree_src->nodes.first; node_dst; node_dst = node_dst->next, node_src = node_src->next) {
+ if (node_dst->parent) {
+ node_dst->parent = node_dst->parent->new_node;
+ }
}
-
- /* node tree will generate its own interface type */
- newtree->interface_type = NULL;
-
- BKE_id_copy_ensure_local(bmain, &ntree->id, &newtree->id);
- return newtree;
+ /* node tree will generate its own interface type */
+ ntree_dst->interface_type = NULL;
}
-bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user)
+bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_id_user)
{
- return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true);
+ bNodeTree *ntree_copy;
+ BKE_id_copy_ex(bmain, (ID *)ntree, (ID **)&ntree_copy, do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT, false);
+ return ntree_copy;
}
-bNodeTree *ntreeCopyTree(Main *bmain, bNodeTree *ntree)
+bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree)
{
return ntreeCopyTree_ex(ntree, bmain, true);
}
-/* use when duplicating scenes */
-void ntreeSwitchID_ex(bNodeTree *ntree, ID *id_from, ID *id_to, const bool do_id_user)
-{
- bNode *node;
-
- if (id_from == id_to) {
- /* should never happen but may as well skip if it does */
- return;
- }
-
- /* for scene duplication only */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id == id_from) {
- if (do_id_user) {
- id_us_min(id_from);
- id_us_plus(id_to);
- }
-
- node->id = id_to;
- }
- }
-}
-void ntreeSwitchID(bNodeTree *ntree, ID *id_from, ID *id_to)
-{
- ntreeSwitchID_ex(ntree, id_from, id_to, true);
-}
-
void ntreeUserIncrefID(bNodeTree *ntree)
{
bNode *node;
@@ -1724,11 +1697,12 @@ static void node_free_node_ex(bNodeTree *ntree, bNode *node, bool remove_animdat
ntreeTexEndExecTree(ntree->execdata);
ntree->execdata = NULL;
}
-
- if (node->typeinfo->freefunc)
- node->typeinfo->freefunc(node);
}
-
+
+ if (node->typeinfo->freefunc) {
+ node->typeinfo->freefunc(node);
+ }
+
for (sock = node->inputs.first; sock; sock = nextsock) {
nextsock = sock->next;
node_socket_free(ntree, sock, node);
@@ -1854,7 +1828,7 @@ void ntreeFreeTree(bNodeTree *ntree)
if (tntree == ntree)
break;
if (tntree == NULL) {
- BKE_libblock_free_data(G.main, &ntree->id);
+ BKE_libblock_free_data(&ntree->id, true);
}
}
@@ -2017,10 +1991,11 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
adt->tmpact = NULL;
}
- /* Make full copy.
+ /* Make full copy outside of Main database.
* Note: previews are not copied here.
*/
- ltree = ntreeCopyTree_internal(ntree, G.main, true, false, false, false);
+ BKE_id_copy_ex(G.main, (ID *)ntree, (ID **)&ltree,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_COPY_NO_PREVIEW, false);
ltree->flag |= NTREE_IS_LOCALIZED;
for (node = ltree->nodes.first; node; node = node->next) {
@@ -2260,7 +2235,7 @@ static void ntree_interface_type_create(bNodeTree *ntree)
/* register a subtype of PropertyGroup */
srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_PropertyGroup);
RNA_def_struct_ui_text(srna, name, description);
- RNA_def_struct_duplicate_pointers(srna);
+ RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna);
/* associate the RNA type with the node tree */
ntree->interface_type = srna;
@@ -2299,10 +2274,10 @@ StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create)
ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description);
/* rename the RNA type */
- RNA_def_struct_free_pointers(srna);
- RNA_def_struct_identifier(srna, identifier);
+ RNA_def_struct_free_pointers(&BLENDER_RNA, srna);
+ RNA_def_struct_identifier(&BLENDER_RNA, srna, identifier);
RNA_def_struct_ui_text(srna, name, description);
- RNA_def_struct_duplicate_pointers(srna);
+ RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna);
}
}
else if (create) {
@@ -3198,12 +3173,20 @@ void nodeSynchronizeID(bNode *node, bool copy_to_id)
void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
{
- if (node->label[0] != '\0')
+ if (node->label[0] != '\0') {
BLI_strncpy(label, node->label, maxlen);
- else if (node->typeinfo->labelfunc)
+ }
+ else if (node->typeinfo->labelfunc) {
node->typeinfo->labelfunc(ntree, node, label, maxlen);
- else
- BLI_strncpy(label, IFACE_(node->typeinfo->ui_name), maxlen);
+ }
+ else {
+ /* Kind of hacky and weak... Ideally would be better to use RNA here. :| */
+ const char *tmp = CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, node->typeinfo->ui_name);
+ if (tmp == node->typeinfo->ui_name) {
+ tmp = IFACE_(node->typeinfo->ui_name);
+ }
+ BLI_strncpy(label, tmp, maxlen);
+ }
}
static void node_type_base_defaults(bNodeType *ntype)
@@ -3594,6 +3577,7 @@ static void registerShaderNodes(void)
register_node_type_sh_background();
register_node_type_sh_bsdf_anisotropic();
register_node_type_sh_bsdf_diffuse();
+ register_node_type_sh_bsdf_principled();
register_node_type_sh_bsdf_glossy();
register_node_type_sh_bsdf_glass();
register_node_type_sh_bsdf_translucent();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 4489ca907f6..44058c989ff 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -127,6 +127,7 @@
#endif
#include "CCGSubSurf.h"
+#include "atomic_ops.h"
#include "GPU_material.h"
@@ -246,6 +247,10 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
mti = modifierType_getInfo(modifier_type);
+ /* only geometry objects should be able to get modifiers [#25291] */
+ if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ return false;
+ }
if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
return false;
@@ -307,7 +312,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
modifier_unique_name(&ob_dst->modifiers, nmd);
}
- BKE_object_copy_particlesystems(ob_dst, ob_src);
+ BKE_object_copy_particlesystems(ob_dst, ob_src, 0);
/* TODO: smoke?, cloth? */
}
@@ -315,19 +320,24 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
/* free data derived from mesh, called when mesh changes or is freed */
void BKE_object_free_derived_caches(Object *ob)
{
- /* also serves as signal to remake texspace */
+ /* Also serves as signal to remake texspace.
+ *
+ * NOTE: This function can be called from threads on different objects
+ * sharing same data datablock. So we need to ensure atomic nature of
+ * data modification here.
+ */
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
if (me && me->bb) {
- me->bb->flag |= BOUNDBOX_DIRTY;
+ atomic_fetch_and_or_uint32((uint *)&me->bb->flag, BOUNDBOX_DIRTY);
}
}
else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
Curve *cu = ob->data;
if (cu && cu->bb) {
- cu->bb->flag |= BOUNDBOX_DIRTY;
+ atomic_fetch_and_or_uint32((uint *)&cu->bb->flag, BOUNDBOX_DIRTY);
}
}
@@ -660,7 +670,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
if (!name)
name = get_obdata_defname(type);
- ob = BKE_libblock_alloc(bmain, ID_OB, name);
+ ob = BKE_libblock_alloc(bmain, ID_OB, name, 0);
/* default object vars */
ob->type = type;
@@ -827,7 +837,7 @@ struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene)
#endif /* WITH_GAMEENGINE */
-SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches)
+SoftBody *copy_softbody(const SoftBody *sb, const int flag)
{
SoftBody *sbn;
@@ -835,7 +845,7 @@ SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches)
sbn = MEM_dupallocN(sb);
- if (copy_caches == false) {
+ if ((flag & LIB_ID_COPY_CACHES) == 0) {
sbn->totspring = sbn->totpoint = 0;
sbn->bpoint = NULL;
sbn->bspring = NULL;
@@ -864,7 +874,7 @@ SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches)
sbn->scratch = NULL;
- sbn->pointcache = BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches, copy_caches);
+ sbn->pointcache = BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches, flag);
if (sb->effector_weights)
sbn->effector_weights = MEM_dupallocN(sb->effector_weights);
@@ -872,7 +882,7 @@ SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches)
return sbn;
}
-BulletSoftBody *copy_bulletsoftbody(BulletSoftBody *bsb)
+BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb, const int UNUSED(flag))
{
BulletSoftBody *bsbn;
@@ -883,7 +893,7 @@ BulletSoftBody *copy_bulletsoftbody(BulletSoftBody *bsb)
return bsbn;
}
-ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
+ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int flag)
{
ParticleSystem *psysn;
ParticleData *pa;
@@ -920,7 +930,7 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
if (psys->clmd) {
psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
- modifier_copyData((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd);
+ modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag);
psys->hair_in_dm = psys->hair_out_dm = NULL;
}
@@ -938,7 +948,8 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
BLI_listbase_clear(&psysn->childcachebufs);
psysn->renderdata = NULL;
- psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, false);
+ /* XXX Never copy caches here? */
+ psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag & ~LIB_ID_COPY_CACHES);
/* XXX - from reading existing code this seems correct but intended usage of
* pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
@@ -946,12 +957,14 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
psysn->clmd->point_cache = psysn->pointcache;
}
- id_us_plus((ID *)psysn->part);
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)psysn->part);
+ }
return psysn;
}
-void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src)
+void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const int flag)
{
ParticleSystem *psys, *npsys;
ModifierData *md;
@@ -963,7 +976,7 @@ void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src)
BLI_listbase_clear(&ob_dst->particlesystem);
for (psys = ob_src->particlesystem.first; psys; psys = psys->next) {
- npsys = BKE_object_copy_particlesystem(psys);
+ npsys = BKE_object_copy_particlesystem(psys, flag);
BLI_addtail(&ob_dst->particlesystem, npsys);
@@ -1000,23 +1013,25 @@ void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src)
{
if (ob_src->soft) {
ob_dst->softflag = ob_src->softflag;
- ob_dst->soft = copy_softbody(ob_src->soft, false);
+ ob_dst->soft = copy_softbody(ob_src->soft, 0);
}
}
-static void copy_object_pose(Object *obn, Object *ob)
+static void copy_object_pose(Object *obn, const Object *ob, const int flag)
{
bPoseChannel *chan;
/* note: need to clear obn->pose pointer first, so that BKE_pose_copy_data works (otherwise there's a crash) */
obn->pose = NULL;
- BKE_pose_copy_data(&obn->pose, ob->pose, 1); /* 1 = copy constraints */
+ BKE_pose_copy_data_ex(&obn->pose, ob->pose, flag, true); /* true = copy constraints */
for (chan = obn->pose->chanbase.first; chan; chan = chan->next) {
bConstraint *con;
chan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
+ /* XXX Remapping object pointing onto itself should be handled by generic BKE_library_remap stuff, but...
+ * the flush_constraint_targets callback am not sure about, so will delay that for now. */
for (con = chan->constraints.first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
@@ -1037,13 +1052,10 @@ static void copy_object_pose(Object *obn, Object *ob)
}
}
-static void copy_object_lod(Object *obn, Object *ob)
+static void copy_object_lod(Object *obn, const Object *ob, const int UNUSED(flag))
{
BLI_duplicatelist(&obn->lodlevels, &ob->lodlevels);
- if (obn->lodlevels.first)
- ((LodLevel *)obn->lodlevels.first)->source = obn;
-
obn->currentlod = (LodLevel *)obn->lodlevels.first;
}
@@ -1088,97 +1100,99 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
copy_v3_v3(ob_tar->size, ob_src->size);
}
-Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
+/**
+ * Only copy internal data of Object ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_src, const int flag)
{
- Object *obn;
ModifierData *md;
- int a;
- obn = BKE_libblock_copy(bmain, &ob->id);
-
- if (ob->totcol) {
- obn->mat = MEM_dupallocN(ob->mat);
- obn->matbits = MEM_dupallocN(ob->matbits);
- obn->totcol = ob->totcol;
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+
+ if (ob_src->totcol) {
+ ob_dst->mat = MEM_dupallocN(ob_src->mat);
+ ob_dst->matbits = MEM_dupallocN(ob_src->matbits);
+ ob_dst->totcol = ob_src->totcol;
}
- if (ob->iuser) obn->iuser = MEM_dupallocN(ob->iuser);
+ if (ob_src->iuser) ob_dst->iuser = MEM_dupallocN(ob_src->iuser);
- if (ob->bb) obn->bb = MEM_dupallocN(ob->bb);
- obn->flag &= ~OB_FROMGROUP;
+ if (ob_src->bb) ob_dst->bb = MEM_dupallocN(ob_src->bb);
+ ob_dst->flag &= ~OB_FROMGROUP;
- BLI_listbase_clear(&obn->modifiers);
+ BLI_listbase_clear(&ob_dst->modifiers);
- for (md = ob->modifiers.first; md; md = md->next) {
+ for (md = ob_src->modifiers.first; md; md = md->next) {
ModifierData *nmd = modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
- modifier_copyData(md, nmd);
- BLI_addtail(&obn->modifiers, nmd);
+ modifier_copyData_ex(md, nmd, flag_subdata);
+ BLI_addtail(&ob_dst->modifiers, nmd);
}
- BLI_listbase_clear(&obn->prop);
- BKE_bproperty_copy_list(&obn->prop, &ob->prop);
+ BLI_listbase_clear(&ob_dst->prop);
+ BKE_bproperty_copy_list(&ob_dst->prop, &ob_src->prop);
- BKE_sca_logic_copy(obn, ob);
+ BKE_sca_logic_copy(ob_dst, ob_src, flag_subdata);
- if (ob->pose) {
- copy_object_pose(obn, ob);
+ if (ob_src->pose) {
+ copy_object_pose(ob_dst, ob_src, flag_subdata);
/* backwards compat... non-armatures can get poses in older files? */
- if (ob->type == OB_ARMATURE)
- BKE_pose_rebuild(obn, obn->data);
+ if (ob_src->type == OB_ARMATURE)
+ BKE_pose_rebuild(ob_dst, ob_dst->data);
}
- defgroup_copy_list(&obn->defbase, &ob->defbase);
- BKE_constraints_copy(&obn->constraints, &ob->constraints, true);
+ defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase);
+ BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true);
- obn->mode = OB_MODE_OBJECT;
- obn->sculpt = NULL;
+ ob_dst->mode = OB_MODE_OBJECT;
+ ob_dst->sculpt = NULL;
- /* increase user numbers */
- id_us_plus((ID *)obn->data);
- id_us_plus((ID *)obn->gpd);
- id_us_plus((ID *)obn->dup_group);
-
- for (a = 0; a < obn->totcol; a++) id_us_plus((ID *)obn->mat[a]);
-
- if (ob->pd) {
- obn->pd = MEM_dupallocN(ob->pd);
- if (obn->pd->tex)
- id_us_plus(&(obn->pd->tex->id));
- if (obn->pd->rng)
- obn->pd->rng = MEM_dupallocN(ob->pd->rng);
+ if (ob_src->pd) {
+ ob_dst->pd = MEM_dupallocN(ob_src->pd);
+ if (ob_dst->pd->rng) {
+ ob_dst->pd->rng = MEM_dupallocN(ob_src->pd->rng);
+ }
}
- obn->soft = copy_softbody(ob->soft, copy_caches);
- obn->bsoft = copy_bulletsoftbody(ob->bsoft);
- obn->rigidbody_object = BKE_rigidbody_copy_object(ob);
- obn->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob);
+ ob_dst->soft = copy_softbody(ob_src->soft, flag_subdata);
+ ob_dst->bsoft = copy_bulletsoftbody(ob_src->bsoft, flag_subdata);
+ ob_dst->rigidbody_object = BKE_rigidbody_copy_object(ob_src, flag_subdata);
+ ob_dst->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob_src, flag_subdata);
- BKE_object_copy_particlesystems(obn, ob);
+ BKE_object_copy_particlesystems(ob_dst, ob_src, flag_subdata);
- obn->derivedDeform = NULL;
- obn->derivedFinal = NULL;
+ ob_dst->derivedDeform = NULL;
+ ob_dst->derivedFinal = NULL;
- BLI_listbase_clear(&obn->gpulamp);
- BLI_listbase_clear(&obn->pc_ids);
+ BLI_listbase_clear(&ob_dst->gpulamp);
+ BLI_listbase_clear(&ob_dst->pc_ids);
- obn->mpath = NULL;
+ ob_dst->mpath = NULL;
- copy_object_lod(obn, ob);
+ copy_object_lod(ob_dst, ob_src, flag_subdata);
- /* Copy runtime surve data. */
- obn->curve_cache = NULL;
-
- BKE_id_copy_ensure_local(bmain, &ob->id, &obn->id);
+ /* Do not copy runtime curve data. */
+ ob_dst->curve_cache = NULL;
/* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */
- obn->preview = NULL;
-
- return obn;
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
+ BKE_previewimg_id_copy(&ob_dst->id, &ob_src->id);
+ }
+ else {
+ ob_dst->preview = NULL;
+ }
}
/* copy objects, will re-initialize cached simulation data */
-Object *BKE_object_copy(Main *bmain, Object *ob)
+Object *BKE_object_copy(Main *bmain, const Object *ob)
{
- return BKE_object_copy_ex(bmain, ob, false);
+ Object *ob_copy;
+ BKE_id_copy_ex(bmain, &ob->id, (ID **)&ob_copy, 0, false);
+ return ob_copy;
}
void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, const bool clear_proxy)
@@ -1200,7 +1214,7 @@ void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, con
if (lib_local || is_local) {
if (!is_lib) {
id_clear_lib_data(bmain, &ob->id);
- BKE_id_expand_local(&ob->id);
+ BKE_id_expand_local(bmain, &ob->id);
if (clear_proxy) {
if (ob->proxy_from != NULL) {
ob->proxy_from->proxy = NULL;
@@ -1215,6 +1229,9 @@ void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, con
ob_new->id.us = 0;
ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(ob, ob_new);
+
if (!lib_local) {
BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
@@ -1373,7 +1390,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
/* type conversions */
if (target->type == OB_ARMATURE) {
- copy_object_pose(ob, target); /* data copy, object pointers in constraints */
+ copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */
BKE_pose_rest(ob->pose); /* clear all transforms in channels */
BKE_pose_rebuild(ob, ob->data); /* set all internal links */
@@ -2229,78 +2246,6 @@ void BKE_boundbox_minmax(const BoundBox *bb, float obmat[4][4], float r_min[3],
}
}
-void BKE_boundbox_scale(struct BoundBox *bb_dst, const struct BoundBox *bb_src, float scale)
-{
- float cent[3];
- BKE_boundbox_calc_center_aabb(bb_src, cent);
-
- for (int i = 0; i < ARRAY_SIZE(bb_dst->vec); i++) {
- bb_dst->vec[i][0] = ((bb_src->vec[i][0] - cent[0]) * scale) + cent[0];
- bb_dst->vec[i][1] = ((bb_src->vec[i][1] - cent[1]) * scale) + cent[1];
- bb_dst->vec[i][2] = ((bb_src->vec[i][2] - cent[2]) * scale) + cent[2];
- }
-}
-
-/**
- * Returns a BBox which each dimensions are at least epsilon.
- * \note In case a given dimension needs to be enlarged, its final value will be in [epsilon, 3 * epsilon] range.
- *
- * \param bb the input bbox to check.
- * \param bb_temp the temp bbox to modify (\a bb content is never changed).
- * \param epsilon the minimum dimension to ensure.
- * \return either bb (if nothing needed to be changed) or bb_temp.
- */
-BoundBox *BKE_boundbox_ensure_minimum_dimensions(BoundBox *bb, BoundBox *bb_temp, const float epsilon)
-{
- if (fabsf(bb->vec[0][0] - bb->vec[4][0]) < epsilon) {
- /* Flat along X axis... */
- *bb_temp = *bb;
- bb = bb_temp;
- bb->vec[0][0] -= epsilon;
- bb->vec[1][0] -= epsilon;
- bb->vec[2][0] -= epsilon;
- bb->vec[3][0] -= epsilon;
- bb->vec[4][0] += epsilon;
- bb->vec[5][0] += epsilon;
- bb->vec[6][0] += epsilon;
- bb->vec[7][0] += epsilon;
- }
-
- if (fabsf(bb->vec[0][1] - bb->vec[3][1]) < epsilon) {
- /* Flat along Y axis... */
- if (bb != bb_temp) {
- *bb_temp = *bb;
- bb = bb_temp;
- }
- bb->vec[0][1] -= epsilon;
- bb->vec[1][1] -= epsilon;
- bb->vec[4][1] -= epsilon;
- bb->vec[5][1] -= epsilon;
- bb->vec[2][1] += epsilon;
- bb->vec[3][1] += epsilon;
- bb->vec[6][1] += epsilon;
- bb->vec[7][1] += epsilon;
- }
-
- if (fabsf(bb->vec[0][2] - bb->vec[1][2]) < epsilon) {
- /* Flat along Z axis... */
- if (bb != bb_temp) {
- *bb_temp = *bb;
- bb = bb_temp;
- }
- bb->vec[0][2] -= epsilon;
- bb->vec[3][2] -= epsilon;
- bb->vec[4][2] -= epsilon;
- bb->vec[7][2] -= epsilon;
- bb->vec[1][2] += epsilon;
- bb->vec[2][2] += epsilon;
- bb->vec[5][2] += epsilon;
- bb->vec[6][2] += epsilon;
- }
-
- return bb;
-}
-
BoundBox *BKE_object_boundbox_get(Object *ob)
{
BoundBox *bb = NULL;
@@ -2737,7 +2682,7 @@ void BKE_object_sculpt_modifiers_changed(Object *ob)
{
SculptSession *ss = ob->sculpt;
- if (ss) {
+ if (ss && ss->building_vp_handle == false) {
if (!ss->cache) {
/* we free pbvh on changes, except during sculpt since it can't deal with
* changing PVBH node organization, we hope topology does not change in
@@ -2748,6 +2693,9 @@ void BKE_object_sculpt_modifiers_changed(Object *ob)
}
BKE_sculptsession_free_deformMats(ob->sculpt);
+
+ /* In vertex/weight paint, force maps to be rebuilt. */
+ BKE_sculptsession_free_vwpaint_data(ob->sculpt);
}
else {
PBVHNode **nodes;
@@ -2809,45 +2757,6 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
return 1;
}
-/*
- * Test a bounding box for ray intersection
- * assumes the ray is already local to the boundbox space
- */
-bool BKE_boundbox_ray_hit_check(
- const struct BoundBox *bb,
- const float ray_start[3], const float ray_normal[3],
- float *r_lambda)
-{
- const int triangle_indexes[12][3] = {
- {0, 1, 2}, {0, 2, 3},
- {3, 2, 6}, {3, 6, 7},
- {1, 2, 6}, {1, 6, 5},
- {5, 6, 7}, {4, 5, 7},
- {0, 3, 7}, {0, 4, 7},
- {0, 1, 5}, {0, 4, 5}};
-
- bool result = false;
- int i;
-
- for (i = 0; i < 12 && (!result || r_lambda); i++) {
- float lambda;
- int v1, v2, v3;
- v1 = triangle_indexes[i][0];
- v2 = triangle_indexes[i][1];
- v3 = triangle_indexes[i][2];
- if (isect_ray_tri_v3(ray_start, ray_normal, bb->vec[v1], bb->vec[v2], bb->vec[v3], &lambda, NULL) &&
- (!r_lambda || *r_lambda > lambda))
- {
- result = true;
- if (r_lambda) {
- *r_lambda = lambda;
- }
- }
- }
-
- return result;
-}
-
static int pc_cmp(const void *a, const void *b)
{
const LinkData *ad = a, *bd = b;
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index b5e1ded35bb..d387e30050c 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -32,6 +32,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
+#include "BLI_string_utils.h"
#include "DNA_armature_types.h"
#include "DNA_cloth_types.h"
@@ -480,6 +481,8 @@ bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_t
*dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw;
return true;
}
+ default:
+ break;
}
}
@@ -623,7 +626,7 @@ void BKE_object_defgroup_mirror_selection(
if (dg_selection[i]) {
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, defgroup->name, false);
+ BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
i_mirr = STREQ(name_flip, defgroup->name) ? i : defgroup_name_index(ob, name_flip);
if ((i_mirr >= 0 && i_mirr < defbase_tot) && (dg_flags_sel[i_mirr] == false)) {
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 14cc5ec0849..b49e481b068 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -64,6 +64,7 @@
#include "BLI_strict_flags.h"
+#include "BLI_hash.h"
/* Dupli-Geometry */
@@ -180,6 +181,23 @@ static DupliObject *make_dupli(const DupliContext *ctx,
if (ob->type == OB_MBALL)
dob->no_draw = true;
+ /* random number */
+ /* the logic here is designed to match Cycles */
+ dob->random_id = BLI_hash_string(dob->ob->id.name + 2);
+
+ if (dob->persistent_id[0] != INT_MAX) {
+ for (i = 0; i < MAX_DUPLI_RECUR * 2; i++) {
+ dob->random_id = BLI_hash_int_2d(dob->random_id, (unsigned int)dob->persistent_id[i]);
+ }
+ }
+ else {
+ dob->random_id = BLI_hash_int_2d(dob->random_id, 0);
+ }
+
+ if (ctx->object != ob) {
+ dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2));
+ }
+
return dob;
}
@@ -325,7 +343,7 @@ static void make_duplis_group(const DupliContext *ctx)
}
}
-const DupliGenerator gen_dupli_group = {
+static const DupliGenerator gen_dupli_group = {
OB_DUPLIGROUP, /* type */
make_duplis_group /* make_duplis */
};
@@ -403,7 +421,7 @@ static void make_duplis_frames(const DupliContext *ctx)
*ob = copyob;
}
-const DupliGenerator gen_dupli_frames = {
+static const DupliGenerator gen_dupli_frames = {
OB_DUPLIFRAMES, /* type */
make_duplis_frames /* make_duplis */
};
@@ -529,10 +547,15 @@ static void make_duplis_verts(const DupliContext *ctx)
BMEditMesh *em = BKE_editmesh_from_object(parent);
CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO : CD_MASK_BAREMESH);
- if (em)
+ if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) {
+ vdd.dm = mesh_create_derived_render(scene, parent, dm_mask);
+ }
+ else if (em) {
vdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
- else
+ }
+ else {
vdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
+ }
vdd.edit_btmesh = me->edit_btmesh;
if (use_texcoords)
@@ -548,7 +571,7 @@ static void make_duplis_verts(const DupliContext *ctx)
vdd.dm->release(vdd.dm);
}
-const DupliGenerator gen_dupli_verts = {
+static const DupliGenerator gen_dupli_verts = {
OB_DUPLIVERTS, /* type */
make_duplis_verts /* make_duplis */
};
@@ -642,8 +665,7 @@ static void make_duplis_font(const DupliContext *ctx)
float rmat[4][4];
zero_v3(obmat[3]);
- unit_m4(rmat);
- rotate_m4(rmat, 'Z', -ct->rot);
+ axis_angle_to_mat4_single(rmat, 'Z', -ct->rot);
mul_m4_m4m4(obmat, obmat, rmat);
}
@@ -662,7 +684,7 @@ static void make_duplis_font(const DupliContext *ctx)
MEM_freeN(chartransdata);
}
-const DupliGenerator gen_dupli_verts_font = {
+static const DupliGenerator gen_dupli_verts_font = {
OB_DUPLIVERTS, /* type */
make_duplis_font /* make_duplis */
};
@@ -793,10 +815,15 @@ static void make_duplis_faces(const DupliContext *ctx)
BMEditMesh *em = BKE_editmesh_from_object(parent);
CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO | CD_MASK_MLOOPUV : CD_MASK_BAREMESH);
- if (em)
+ if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) {
+ fdd.dm = mesh_create_derived_render(scene, parent, dm_mask);
+ }
+ else if (em) {
fdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
- else
+ }
+ else {
fdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
+ }
if (use_texcoords) {
CustomData *ml_data = fdd.dm->getLoopDataLayout(fdd.dm);
@@ -820,7 +847,7 @@ static void make_duplis_faces(const DupliContext *ctx)
fdd.dm->release(fdd.dm);
}
-const DupliGenerator gen_dupli_faces = {
+static const DupliGenerator gen_dupli_faces = {
OB_DUPLIFACES, /* type */
make_duplis_faces /* make_duplis */
};
@@ -1141,7 +1168,7 @@ static void make_duplis_particles(const DupliContext *ctx)
}
}
-const DupliGenerator gen_dupli_particles = {
+static const DupliGenerator gen_dupli_particles = {
OB_DUPLIPARTS, /* type */
make_duplis_particles /* make_duplis */
};
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 5cb704e4737..e03af585cf2 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -54,6 +54,7 @@
#include "BKE_editmesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
+#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_material.h"
#include "BKE_image.h"
@@ -144,18 +145,6 @@ void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob)
else ob->transflag &= ~OB_NEG_SCALE;
}
-void BKE_object_eval_modifier(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- struct ModifierData *md)
-{
- DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
- (void) eval_ctx; /* Ignored. */
- (void) scene; /* Ignored. */
- (void) ob; /* Ignored. */
- (void) md; /* Ignored. */
-}
-
void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
Scene *scene,
Object *ob)
@@ -347,3 +336,9 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx,
ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
}
+
+void BKE_object_eval_cloth(EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *object)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, object->id.name);
+ BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
+}
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 621ac9c2480..537c8926a5b 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -334,10 +334,10 @@ void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float
i1 = i1 % oc->_M;
j1 = j1 % oc->_N;
-
#define BILERP(m) (interpf(interpf(m[i1 * oc->_N + j1], m[i0 * oc->_N + j1], frac_x), \
interpf(m[i1 * oc->_N + j0], m[i0 * oc->_N + j0], frac_x), \
frac_z))
+
{
if (oc->_do_disp_y) {
ocr->disp[1] = BILERP(oc->_disp_y);
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 489fc2f3710..89f25136caf 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -450,7 +450,7 @@ char *unpackFile(ReportList *reports, const char *abs_name, const char *local_na
break;
}
/* else create it */
- /* fall-through */
+ ATTR_FALLTHROUGH;
}
case PF_WRITE_LOCAL:
if (writePackedFile(reports, local_name, pf, 1) == RET_OK) {
@@ -471,7 +471,7 @@ char *unpackFile(ReportList *reports, const char *abs_name, const char *local_na
break;
}
/* else create it */
- /* fall-through */
+ ATTR_FALLTHROUGH;
}
case PF_WRITE_ORIGINAL:
if (writePackedFile(reports, abs_name, pf, 1) == RET_OK) {
@@ -522,6 +522,8 @@ static void unpack_generate_paths(
case ID_IM:
BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname);
break;
+ default:
+ break;
}
{
@@ -712,6 +714,8 @@ bool BKE_pack_check(ID *id)
Library *li = (Library *)id;
return li->packedfile != NULL;
}
+ default:
+ break;
}
return false;
}
@@ -750,5 +754,7 @@ void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how)
BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->name);
break;
}
+ default:
+ break;
}
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 6b954f060d3..62af61585c1 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -49,6 +49,7 @@
#include "BKE_brush.h"
#include "BKE_colortools.h"
+#include "BKE_deform.h"
#include "BKE_main.h"
#include "BKE_context.h"
#include "BKE_crazyspace.h"
@@ -309,24 +310,31 @@ PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name)
{
PaintCurve *pc;
- pc = BKE_libblock_alloc(bmain, ID_PC, name);
+ pc = BKE_libblock_alloc(bmain, ID_PC, name, 0);
return pc;
}
-PaintCurve *BKE_paint_curve_copy(Main *bmain, PaintCurve *pc)
+/**
+ * Only copy internal data of PaintCurve ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_paint_curve_copy_data(Main *UNUSED(bmain), PaintCurve *pc_dst, const PaintCurve *pc_src, const int UNUSED(flag))
{
- PaintCurve *pc_new;
-
- pc_new = BKE_libblock_copy(bmain, &pc->id);
-
- if (pc->tot_points != 0) {
- pc_new->points = MEM_dupallocN(pc->points);
+ if (pc_src->tot_points != 0) {
+ pc_dst->points = MEM_dupallocN(pc_src->points);
}
+}
- BKE_id_copy_ensure_local(bmain, &pc->id, &pc_new->id);
-
- return pc_new;
+PaintCurve *BKE_paint_curve_copy(Main *bmain, const PaintCurve *pc)
+{
+ PaintCurve *pc_copy;
+ BKE_id_copy_ex(bmain, &pc->id, (ID **)&pc_copy, 0, false);
+ return pc_copy;
}
void BKE_paint_curve_make_local(Main *bmain, PaintCurve *pc, const bool lib_local)
@@ -388,7 +396,7 @@ Palette *BKE_palette_add(Main *bmain, const char *name)
{
Palette *palette;
- palette = BKE_libblock_alloc(bmain, ID_PAL, name);
+ palette = BKE_libblock_alloc(bmain, ID_PAL, name, 0);
/* enable fake user by default */
id_fake_user_set(&palette->id);
@@ -396,17 +404,24 @@ Palette *BKE_palette_add(Main *bmain, const char *name)
return palette;
}
-Palette *BKE_palette_copy(Main *bmain, Palette *palette)
+/**
+ * Only copy internal data of Palette ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_palette_copy_data(Main *UNUSED(bmain), Palette *palette_dst, const Palette *palette_src, const int UNUSED(flag))
{
- Palette *palette_new;
-
- palette_new = BKE_libblock_copy(bmain, &palette->id);
-
- BLI_duplicatelist(&palette_new->colors, &palette->colors);
-
- BKE_id_copy_ensure_local(bmain, &palette->id, &palette_new->id);
+ BLI_duplicatelist(&palette_dst->colors, &palette_src->colors);
+}
- return palette_new;
+Palette *BKE_palette_copy(Main *bmain, const Palette *palette)
+{
+ Palette *palette_copy;
+ BKE_id_copy_ex(bmain, &palette->id, (ID **)&palette_copy, 0, false);
+ return palette_copy;
}
void BKE_palette_make_local(Main *bmain, Palette *palette, const bool lib_local)
@@ -452,7 +467,7 @@ bool BKE_paint_select_vert_test(Object *ob)
(ob->type == OB_MESH) &&
(ob->data != NULL) &&
(((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_VERT_SEL) &&
- (ob->mode & OB_MODE_WEIGHT_PAINT)
+ (ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT)
);
}
@@ -537,12 +552,15 @@ void BKE_paint_free(Paint *paint)
* still do a id_us_plus(), rather then if we were copying between 2 existing
* scenes where a matching value should decrease the existing user count as
* with paint_brush_set() */
-void BKE_paint_copy(Paint *src, Paint *tar)
+void BKE_paint_copy(Paint *src, Paint *tar, const int flag)
{
tar->brush = src->brush;
- id_us_plus((ID *)tar->brush);
- id_us_plus((ID *)tar->palette);
tar->cavity_curve = curvemapping_copy(src->cavity_curve);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)tar->brush);
+ id_us_plus((ID *)tar->palette);
+ }
}
void BKE_paint_stroke_get_average(Scene *scene, Object *ob, float stroke[3])
@@ -656,6 +674,33 @@ void BKE_sculptsession_free_deformMats(SculptSession *ss)
MEM_SAFE_FREE(ss->deform_imats);
}
+void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss)
+{
+ struct SculptVertexPaintGeomMap *gmap = NULL;
+ if (ss->mode_type == OB_MODE_VERTEX_PAINT) {
+ gmap = &ss->mode.vpaint.gmap;
+
+ MEM_SAFE_FREE(ss->mode.vpaint.previous_color);
+ }
+ else if (ss->mode_type == OB_MODE_WEIGHT_PAINT) {
+ gmap = &ss->mode.wpaint.gmap;
+
+ MEM_SAFE_FREE(ss->mode.wpaint.alpha_weight);
+ if (ss->mode.wpaint.dvert_prev) {
+ BKE_defvert_array_free_elems(ss->mode.wpaint.dvert_prev, ss->totvert);
+ MEM_freeN(ss->mode.wpaint.dvert_prev);
+ ss->mode.wpaint.dvert_prev = NULL;
+ }
+ }
+ else {
+ return;
+ }
+ MEM_SAFE_FREE(gmap->vert_to_loop);
+ MEM_SAFE_FREE(gmap->vert_map_mem);
+ MEM_SAFE_FREE(gmap->vert_to_poly);
+ MEM_SAFE_FREE(gmap->poly_map_mem);
+}
+
/* Write out the sculpt dynamic-topology BMesh to the Mesh */
static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
{
@@ -747,6 +792,8 @@ void BKE_sculptsession_free(Object *ob)
if (ss->deform_imats)
MEM_freeN(ss->deform_imats);
+ BKE_sculptsession_free_vwpaint_data(ob->sculpt);
+
MEM_freeN(ss);
ob->sculpt = NULL;
@@ -831,6 +878,8 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob);
ss->show_diffuse_color = (sd->flags & SCULPT_SHOW_DIFFUSE) != 0;
+ ss->building_vp_handle = false;
+
if (need_mask) {
if (mmd == NULL) {
if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) {
@@ -859,7 +908,8 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- if (mmd) {
+ /* VWPaint require mesh info for loop lookup, so require sculpt mode here */
+ if (mmd && ob->mode & OB_MODE_SCULPT) {
ss->multires = mmd;
ss->totvert = dm->getNumVerts(dm);
ss->totpoly = dm->getNumPolys(dm);
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 1ea27558545..8c94cdfe784 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -253,11 +253,16 @@ struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData
if (psys_in_edit_mode(sim->scene, sim->psys) == 0) {
Object *lattice = NULL;
ModifierData *md = (ModifierData *)psys_get_modifier(sim->ob, sim->psys);
+ int mode = G.is_rendering ? eModifierMode_Render : eModifierMode_Realtime;
for (; md; md = md->next) {
if (md->type == eModifierType_Lattice) {
- LatticeModifierData *lmd = (LatticeModifierData *)md;
- lattice = lmd->object;
+ if (md->mode & mode) {
+ LatticeModifierData *lmd = (LatticeModifierData *)md;
+ lattice = lmd->object;
+ sim->psys->lattice_strength = lmd->strength;
+ }
+
break;
}
}
@@ -590,7 +595,7 @@ void psys_free(Object *ob, ParticleSystem *psys)
BLI_bvhtree_free(psys->bvhtree);
BLI_kdtree_free(psys->tree);
-
+
if (psys->fluid_springs)
MEM_freeN(psys->fluid_springs);
@@ -633,8 +638,9 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], floa
data->childcachebufs.last = psys->childcachebufs.last;
data->totchildcache = psys->totchildcache;
- if (psmd->dm_final)
- data->dm = CDDM_copy(psmd->dm_final);
+ if (psmd->dm_final) {
+ data->dm = CDDM_copy_with_tessface(psmd->dm_final);
+ }
data->totdmvert = psmd->totdmvert;
data->totdmedge = psmd->totdmedge;
data->totdmface = psmd->totdmface;
@@ -2705,7 +2711,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
/* lattices have to be calculated separately to avoid mixups between effector calculations */
if (psys->lattice_deform_data) {
for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
- calc_latt_deform(psys->lattice_deform_data, ca->co, 1.0f);
+ calc_latt_deform(psys->lattice_deform_data, ca->co, psys->lattice_strength);
}
}
@@ -3294,7 +3300,7 @@ ParticleSettings *psys_new_settings(const char *name, Main *main)
if (main == NULL)
main = G.main;
- part = BKE_libblock_alloc(main, ID_PA, name);
+ part = BKE_libblock_alloc(main, ID_PA, name, 0);
default_particle_settings(part);
@@ -3325,38 +3331,45 @@ void BKE_particlesettings_rough_curve_init(ParticleSettings *part)
part->roughcurve = cumap;
}
-ParticleSettings *BKE_particlesettings_copy(Main *bmain, ParticleSettings *part)
+/**
+ * Only copy internal data of ParticleSettings ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_particlesettings_copy_data(
+ Main *UNUSED(bmain), ParticleSettings *part_dst, const ParticleSettings *part_src, const int UNUSED(flag))
{
- ParticleSettings *partn;
- int a;
-
- partn = BKE_libblock_copy(bmain, &part->id);
+ part_dst->pd = MEM_dupallocN(part_src->pd);
+ part_dst->pd2 = MEM_dupallocN(part_src->pd2);
+ part_dst->effector_weights = MEM_dupallocN(part_src->effector_weights);
+ part_dst->fluid = MEM_dupallocN(part_src->fluid);
- partn->pd = MEM_dupallocN(part->pd);
- partn->pd2 = MEM_dupallocN(part->pd2);
- partn->effector_weights = MEM_dupallocN(part->effector_weights);
- partn->fluid = MEM_dupallocN(part->fluid);
+ if (part_src->clumpcurve) {
+ part_dst->clumpcurve = curvemapping_copy(part_src->clumpcurve);
+ }
+ if (part_src->roughcurve) {
+ part_dst->roughcurve = curvemapping_copy(part_src->roughcurve);
+ }
- if (part->clumpcurve)
- partn->clumpcurve = curvemapping_copy(part->clumpcurve);
- if (part->roughcurve)
- partn->roughcurve = curvemapping_copy(part->roughcurve);
-
- partn->boids = boid_copy_settings(part->boids);
+ part_dst->boids = boid_copy_settings(part_src->boids);
- for (a = 0; a < MAX_MTEX; a++) {
- if (part->mtex[a]) {
- partn->mtex[a] = MEM_mallocN(sizeof(MTex), "psys_copy_tex");
- memcpy(partn->mtex[a], part->mtex[a], sizeof(MTex));
- id_us_plus((ID *)partn->mtex[a]->tex);
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (part_src->mtex[a]) {
+ part_dst->mtex[a] = MEM_dupallocN(part_src->mtex[a]);
}
}
- BLI_duplicatelist(&partn->dupliweights, &part->dupliweights);
-
- BKE_id_copy_ensure_local(bmain, &part->id, &partn->id);
+ BLI_duplicatelist(&part_dst->dupliweights, &part_src->dupliweights);
+}
- return partn;
+ParticleSettings *BKE_particlesettings_copy(Main *bmain, const ParticleSettings *part)
+{
+ ParticleSettings *part_copy;
+ BKE_id_copy_ex(bmain, &part->id, (ID **)&part_copy, 0, false);
+ return part_copy;
}
void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const bool lib_local)
@@ -3368,7 +3381,8 @@ void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const
/* Textures */
/************************************************/
-static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, const float fuv[4], char *name, float *texco)
+static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const float fuv[4],
+ char *name, float *texco, bool from_vert)
{
MFace *mf;
MTFace *tf;
@@ -3384,11 +3398,15 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
if (pa) {
i = ELEM(pa->num_dmcache, DMCACHE_NOTFOUND, DMCACHE_ISCHILD) ? pa->num : pa->num_dmcache;
- if (i >= dm->getNumTessFaces(dm))
+ if ((!from_vert && i >= dm->getNumTessFaces(dm)) ||
+ (from_vert && i >= dm->getNumVerts(dm)))
+ {
i = -1;
+ }
+ }
+ else {
+ i = index;
}
- else
- i = face_index;
if (i == -1) {
texco[0] = 0.0f;
@@ -3396,7 +3414,22 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
texco[2] = 0.0f;
}
else {
- mf = dm->getTessFaceData(dm, i, CD_MFACE);
+ if (from_vert) {
+ mf = dm->getTessFaceDataArray(dm, CD_MFACE);
+
+ /* This finds the first face to contain the emitting vertex,
+ * this is not ideal, but is mostly fine as UV seams generally
+ * map to equal-colored parts of a texture */
+ for (int j = 0; j < dm->getNumTessFaces(dm); j++, mf++) {
+ if (ELEM(i, mf->v1, mf->v2, mf->v3, mf->v4)) {
+ i = j;
+ break;
+ }
+ }
+ }
+ else {
+ mf = dm->getTessFaceData(dm, i, CD_MFACE);
+ }
psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco);
@@ -3463,9 +3496,13 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
mul_m4_v3(mtex->object->imat, texvec);
break;
case TEXCO_UV:
- if (fw && get_particle_uv(dm, NULL, face_index, fw, mtex->uvname, texvec))
+ if (fw && get_particle_uv(dm, NULL, face_index, fw, mtex->uvname,
+ texvec, (part->from == PART_FROM_VERT)))
+ {
break;
- /* no break, failed to get uv's, so let's try orco's */
+ }
+ /* no break, failed to get uv's, so let's try orco's */
+ ATTR_FALLTHROUGH;
case TEXCO_ORCO:
copy_v3_v3(texvec, orco);
break;
@@ -3535,9 +3572,13 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
mul_m4_v3(mtex->object->imat, texvec);
break;
case TEXCO_UV:
- if (get_particle_uv(sim->psmd->dm_final, pa, 0, pa->fuv, mtex->uvname, texvec))
+ if (get_particle_uv(sim->psmd->dm_final, pa, 0, pa->fuv, mtex->uvname,
+ texvec, (part->from == PART_FROM_VERT)))
+ {
break;
- /* no break, failed to get uv's, so let's try orco's */
+ }
+ /* no break, failed to get uv's, so let's try orco's */
+ ATTR_FALLTHROUGH;
case TEXCO_ORCO:
psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec, 0);
@@ -3745,7 +3786,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
}
if (psys->lattice_deform_data && edit == 0)
- calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f);
+ calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength);
}
}
}
@@ -3984,7 +4025,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
do_child_modifiers(NULL, sim, NULL, key1->co, key1->vel, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t);
if (psys->lattice_deform_data)
- calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f);
+ calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength);
}
else {
if (pa->state.time == cfra || ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED))
@@ -4043,7 +4084,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
}
if (sim->psys->lattice_deform_data)
- calc_latt_deform(sim->psys->lattice_deform_data, state->co, 1.0f);
+ calc_latt_deform(sim->psys->lattice_deform_data, state->co, psys->lattice_strength);
}
return 1;
@@ -4290,7 +4331,7 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
hkey = pa->hair;
for (h = 0; h < pa->totkey; h++, hkey++) {
mul_m4_v3(hairmat, hkey->co);
- calc_latt_deform(psys->lattice_deform_data, hkey->co, 1.0f);
+ calc_latt_deform(psys->lattice_deform_data, hkey->co, psys->lattice_strength);
mul_m4_v3(imat, hkey->co);
}
}
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index 842de869291..bfcda89a635 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -355,9 +355,13 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
{
const float step_length = 1.0f / (float)(totkeys - 1);
-
float cur_length = 0.0f;
-
+
+ if (max_length <= 0.0f) {
+ keys->segments = -1;
+ totkeys = 0;
+ }
+
/* we have to correct velocity because of kink & clump */
for (k = 0, key = keys; k < totkeys; ++k, ++key) {
if (k >= 2) {
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 44cf5b119c1..9a7980827ad 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -39,6 +39,7 @@
#include "BLI_jitter.h"
#include "BLI_kdtree.h"
#include "BLI_math.h"
+#include "BLI_math_geom.h"
#include "BLI_rand.h"
#include "BLI_sort.h"
#include "BLI_task.h"
@@ -213,14 +214,22 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
copy_v3_v3(co2, co1);
co2[a] += delta[a] + 0.001f*d;
co1[a] -= 0.001f*d;
-
+
+ struct IsectRayPrecalc isect_precalc;
+ float ray_direction[3];
+ sub_v3_v3v3(ray_direction, co2, co1);
+ isect_ray_tri_watertight_v3_precalc(&isect_precalc, ray_direction);
+
/* lets intersect the faces */
for (i=0; i<totface; i++,mface++) {
copy_v3_v3(v1, mvert[mface->v1].co);
copy_v3_v3(v2, mvert[mface->v2].co);
copy_v3_v3(v3, mvert[mface->v3].co);
- bool intersects_tri = isect_axial_line_segment_tri_v3(a, co1, co2, v2, v3, v1, &lambda);
+ bool intersects_tri = isect_ray_tri_watertight_v3(co1,
+ &isect_precalc,
+ v1, v2, v3,
+ &lambda, NULL);
if (intersects_tri) {
if (from==PART_FROM_FACE)
(pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
@@ -231,7 +240,10 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
if (mface->v4 && (!intersects_tri || from==PART_FROM_VOLUME)) {
copy_v3_v3(v4, mvert[mface->v4].co);
- if (isect_axial_line_segment_tri_v3(a, co1, co2, v4, v1, v3, &lambda)) {
+ if (isect_ray_tri_watertight_v3(co1,
+ &isect_precalc,
+ v1, v3, v4,
+ &lambda, NULL)) {
if (from==PART_FROM_FACE)
(pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
else
@@ -427,12 +439,37 @@ static int distribute_binary_search(float *sum, int n, float value)
static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, int p)
{
ParticleThreadContext *ctx= thread->ctx;
- int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+ MFace *mface;
+
+ mface = ctx->dm->getTessFaceDataArray(ctx->dm, CD_MFACE);
+
+ int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
/* TODO_PARTICLE - use original index */
- pa->num= ctx->index[p];
- pa->fuv[0] = 1.0f;
- pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0;
+ pa->num = ctx->index[p];
+
+ zero_v4(pa->fuv);
+
+ if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->dm->getNumVerts(ctx->dm)) {
+
+ /* This finds the first face to contain the emitting vertex,
+ * this is not ideal, but is mostly fine as UV seams generally
+ * map to equal-colored parts of a texture */
+ for (int i = 0; i < ctx->dm->getNumTessFaces(ctx->dm); i++, mface++) {
+ if (ELEM(pa->num, mface->v1, mface->v2, mface->v3, mface->v4)) {
+ unsigned int *vert = &mface->v1;
+
+ for (int j = 0; j < 4; j++, vert++) {
+ if (*vert == pa->num) {
+ pa->fuv[j] = 1.0f;
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ }
#if ONLY_WORKING_WITH_PA_VERTS
if (ctx->tree) {
@@ -873,10 +910,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
else
dm= CDDM_from_mesh((Mesh*)ob->data);
- /* BMESH ONLY, for verts we don't care about tessfaces */
- if (from != PART_FROM_VERT) {
- DM_ensure_tessface(dm);
- }
+ DM_ensure_tessface(dm);
/* we need orco for consistent distributions */
if (!CustomData_has_layer(&dm->vertData, CD_ORCO))
@@ -1070,13 +1104,10 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
/* This is to address tricky issues with vertex-emitting when user tries (and expects) exact 1-1 vert/part
* distribution (see T47983 and its two example files). It allows us to consider pos as
* 'midpoint between v and v+1' (or 'p and p+1', depending whether we have more vertices than particles or not),
- * and avoid stumbling over float imprecisions in element_sum. */
- if (from == PART_FROM_VERT) {
- pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */
- }
- else {
- pos = 0.0;
- }
+ * and avoid stumbling over float imprecisions in element_sum.
+ * Note: moved face and volume distribution to this as well (instead of starting at zero),
+ * for the same reasons, see T52682. */
+ pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */
for (i = 0, p = 0; p < totpart; p++, pos += step) {
for ( ; (i < totmapped - 1) && (pos > (double)element_sum[i]); i++);
@@ -1092,7 +1123,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
/* For hair, sort by origindex (allows optimization's in rendering), */
/* however with virtual parents the children need to be in random order. */
- if (part->type == PART_HAIR && !(part->childtype==PART_CHILD_FACES && part->parents!=0.0f)) {
+ if (part->type == PART_HAIR && !(part->childtype==PART_CHILD_FACES && part->parents != 0.0f)) {
int *orig_index = NULL;
if (from == PART_FROM_VERT) {
@@ -1115,7 +1146,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
if (jitlevel == 0) {
jitlevel= totpart/totelem;
- if (part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */
+ if (part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scientific */
if (jitlevel<3) jitlevel= 3;
}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index ee435051151..38eb861599a 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -1000,7 +1000,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
part=psys->part;
/* get precise emitter matrix if particle is born */
- if (part->type!=PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) {
+ if (part->type != PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) {
evaluate_emitter_anim(sim->scene, sim->ob, pa->time);
psys->flag |= PSYS_OB_ANIM_RESTORE;
@@ -1183,7 +1183,7 @@ static void set_keyed_keys(ParticleSimulationData *sim)
key->time = pa->time;
}
- if (psys->flag & PSYS_KEYED_TIMING && pt->duration!=0.0f)
+ if (psys->flag & PSYS_KEYED_TIMING && pt->duration != 0.0f)
k++;
ksim.psys->flag |= keyed_flag;
@@ -2319,21 +2319,21 @@ static void collision_point_on_surface(float p[3], ParticleCollisionElement *pce
}
case 3:
{
- float p0[3], e1[3], e2[3], nor[3];
+ float p0[3], e1[3], e2[3], nor[3];
- sub_v3_v3v3(e1, pce->x1, pce->x0);
- sub_v3_v3v3(e2, pce->x2, pce->x0);
- sub_v3_v3v3(p0, p, pce->x0);
+ sub_v3_v3v3(e1, pce->x1, pce->x0);
+ sub_v3_v3v3(e2, pce->x2, pce->x0);
+ sub_v3_v3v3(p0, p, pce->x0);
- cross_v3_v3v3(nor, e1, e2);
- normalize_v3(nor);
+ cross_v3_v3v3(nor, e1, e2);
+ normalize_v3(nor);
- if (pce->inv_nor == 1)
- negate_v3(nor);
+ if (pce->inv_nor == 1)
+ negate_v3(nor);
- madd_v3_v3v3fl(co, pce->x0, nor, col->radius);
- madd_v3_v3fl(co, e1, pce->uv[0]);
- madd_v3_v3fl(co, e2, pce->uv[1]);
+ madd_v3_v3v3fl(co, pce->x0, nor, col->radius);
+ madd_v3_v3fl(co, e1, pce->uv[0]);
+ madd_v3_v3fl(co, e2, pce->uv[1]);
break;
}
}
@@ -3042,10 +3042,12 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
/* calculate maximum segment length */
max_length = 0.0f;
LOOP_PARTICLES {
- for (k=1, key=pa->hair+1; k<pa->totkey; k++,key++) {
- float length = len_v3v3(key->co, (key-1)->co);
- if (max_length < length)
- max_length = length;
+ if (!(pa->flag & PARS_UNEXIST)) {
+ for (k=1, key=pa->hair+1; k<pa->totkey; k++,key++) {
+ float length = len_v3v3(key->co, (key-1)->co);
+ if (max_length < length)
+ max_length = length;
+ }
}
}
@@ -3057,76 +3059,78 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
/* make vgroup for pin roots etc.. */
hair_index = 1;
LOOP_PARTICLES {
- float root_mat[4][4];
- float bending_stiffness;
- bool use_hair;
-
- pa->hair_index = hair_index;
- use_hair = psys_hair_use_simulation(pa, max_length);
-
- psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
- mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat);
- normalize_m4(root_mat);
-
- bending_stiffness = CLAMPIS(1.0f - part->bending_random * psys_frand(psys, p + 666), 0.0f, 1.0f);
-
- for (k=0, key=pa->hair; k<pa->totkey; k++,key++) {
- ClothHairData *hair;
- float *co, *co_next;
-
- co = key->co;
- co_next = (key+1)->co;
-
- /* create fake root before actual root to resist bending */
- if (k==0) {
- hair = &psys->clmd->hairdata[pa->hair_index - 1];
+ if (!(pa->flag & PARS_UNEXIST)) {
+ float root_mat[4][4];
+ float bending_stiffness;
+ bool use_hair;
+
+ pa->hair_index = hair_index;
+ use_hair = psys_hair_use_simulation(pa, max_length);
+
+ psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
+ mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat);
+ normalize_m4(root_mat);
+
+ bending_stiffness = CLAMPIS(1.0f - part->bending_random * psys_frand(psys, p + 666), 0.0f, 1.0f);
+
+ for (k=0, key=pa->hair; k<pa->totkey; k++,key++) {
+ ClothHairData *hair;
+ float *co, *co_next;
+
+ co = key->co;
+ co_next = (key+1)->co;
+
+ /* create fake root before actual root to resist bending */
+ if (k==0) {
+ hair = &psys->clmd->hairdata[pa->hair_index - 1];
+ copy_v3_v3(hair->loc, root_mat[3]);
+ copy_m3_m4(hair->rot, root_mat);
+
+ hair->radius = hair_radius;
+ hair->bending_stiffness = bending_stiffness;
+
+ add_v3_v3v3(mvert->co, co, co);
+ sub_v3_v3(mvert->co, co_next);
+ mul_m4_v3(hairmat, mvert->co);
+
+ medge->v1 = pa->hair_index - 1;
+ medge->v2 = pa->hair_index;
+
+ dvert = hair_set_pinning(dvert, 1.0f);
+
+ mvert++;
+ medge++;
+ }
+
+ /* store root transform in cloth data */
+ hair = &psys->clmd->hairdata[pa->hair_index + k];
copy_v3_v3(hair->loc, root_mat[3]);
copy_m3_m4(hair->rot, root_mat);
-
+
hair->radius = hair_radius;
hair->bending_stiffness = bending_stiffness;
-
- add_v3_v3v3(mvert->co, co, co);
- sub_v3_v3(mvert->co, co_next);
+
+ copy_v3_v3(mvert->co, co);
mul_m4_v3(hairmat, mvert->co);
-
- medge->v1 = pa->hair_index - 1;
- medge->v2 = pa->hair_index;
-
- dvert = hair_set_pinning(dvert, 1.0f);
-
+
+ if (k) {
+ medge->v1 = pa->hair_index + k - 1;
+ medge->v2 = pa->hair_index + k;
+ }
+
+ /* roots and disabled hairs should be 1.0, the rest can be anything from 0.0 to 1.0 */
+ if (use_hair)
+ dvert = hair_set_pinning(dvert, key->weight);
+ else
+ dvert = hair_set_pinning(dvert, 1.0f);
+
mvert++;
- medge++;
+ if (k)
+ medge++;
}
-
- /* store root transform in cloth data */
- hair = &psys->clmd->hairdata[pa->hair_index + k];
- copy_v3_v3(hair->loc, root_mat[3]);
- copy_m3_m4(hair->rot, root_mat);
-
- hair->radius = hair_radius;
- hair->bending_stiffness = bending_stiffness;
-
- copy_v3_v3(mvert->co, co);
- mul_m4_v3(hairmat, mvert->co);
-
- if (k) {
- medge->v1 = pa->hair_index + k - 1;
- medge->v2 = pa->hair_index + k;
- }
-
- /* roots and disabled hairs should be 1.0, the rest can be anything from 0.0 to 1.0 */
- if (use_hair)
- dvert = hair_set_pinning(dvert, key->weight);
- else
- dvert = hair_set_pinning(dvert, 1.0f);
-
- mvert++;
- if (k)
- medge++;
+
+ hair_index += pa->totkey + 1;
}
-
- hair_index += pa->totkey + 1;
}
}
@@ -3152,9 +3156,11 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
totpoint = 0;
totedge = 0;
LOOP_PARTICLES {
- /* "out" dm contains all hairs */
- totedge += pa->totkey;
- totpoint += pa->totkey + 1; /* +1 for virtual root point */
+ if (!(pa->flag & PARS_UNEXIST)) {
+ /* "out" dm contains all hairs */
+ totedge += pa->totkey;
+ totpoint += pa->totkey + 1; /* +1 for virtual root point */
+ }
}
realloc_roots = false; /* whether hair root info array has to be reallocated */
@@ -4328,12 +4334,12 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func,
{
ParticleTarget *pt;
- func(psys, (ID **)&psys->part, userdata, IDWALK_USER | IDWALK_NEVER_NULL);
- func(psys, (ID **)&psys->target_ob, userdata, IDWALK_NOP);
- func(psys, (ID **)&psys->parent, userdata, IDWALK_NOP);
+ func(psys, (ID **)&psys->part, userdata, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
+ func(psys, (ID **)&psys->target_ob, userdata, IDWALK_CB_NOP);
+ func(psys, (ID **)&psys->parent, userdata, IDWALK_CB_NOP);
for (pt = psys->targets.first; pt; pt = pt->next) {
- func(psys, (ID **)&pt->ob, userdata, IDWALK_NOP);
+ func(psys, (ID **)&pt->ob, userdata, IDWALK_CB_NOP);
}
/* Even though psys->part should never be NULL, this can happen as an exception during deletion.
@@ -4343,20 +4349,19 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func,
int p;
for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) {
- func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_NOP);
+ func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_CB_NOP);
}
}
}
/* **** Depsgraph evaluation **** */
-void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx),
- Scene *scene,
- Object *ob,
- ParticleSystem *psys)
+void BKE_particle_system_eval_init(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob)
{
if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s on %s:%s\n", __func__, ob->id.name, psys->name);
+ printf("%s on %s\n", __func__, ob->id.name);
}
BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 4fe4d6e75a6..aa8ab07518f 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -34,6 +34,7 @@
#include "BKE_pbvh.h"
#include "BKE_ccg.h"
+#include "BKE_subsurf.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h" /* for BKE_mesh_calc_normals */
@@ -606,6 +607,11 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids,
MEM_freeN(prim_bbc);
}
+void BKE_pbvh_set_ccgdm(PBVH *bvh, CCGDerivedMesh *ccgdm)
+{
+ bvh->ccgdm = ccgdm;
+}
+
PBVH *BKE_pbvh_new(void)
{
PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh");
@@ -620,7 +626,7 @@ void BKE_pbvh_free(PBVH *bvh)
if (node->flag & PBVH_Leaf) {
if (node->draw_buffers)
- GPU_free_pbvh_buffers(node->draw_buffers);
+ GPU_pbvh_buffers_free(node->draw_buffers);
if (node->vert_indices)
MEM_freeN((void *)node->vert_indices);
if (node->face_vert_indices)
@@ -635,7 +641,7 @@ void BKE_pbvh_free(PBVH *bvh)
BLI_gset_free(node->bm_other_verts, NULL);
}
}
- GPU_free_pbvh_buffer_multires(&bvh->grid_common_gpu_buffer);
+ GPU_pbvh_multires_buffers_free(&bvh->grid_common_gpu_buffer);
if (bvh->deformed) {
if (bvh->verts) {
@@ -1090,11 +1096,11 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
PBVHNode *node = nodes[n];
if (node->flag & PBVH_RebuildDrawBuffers) {
- GPU_free_pbvh_buffers(node->draw_buffers);
+ GPU_pbvh_buffers_free(node->draw_buffers);
switch (bvh->type) {
case PBVH_GRIDS:
node->draw_buffers =
- GPU_build_grid_pbvh_buffers(node->prim_indices,
+ GPU_pbvh_grid_buffers_build(node->prim_indices,
node->totprim,
bvh->grid_hidden,
bvh->gridkey.grid_size,
@@ -1102,7 +1108,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
break;
case PBVH_FACES:
node->draw_buffers =
- GPU_build_mesh_pbvh_buffers(node->face_vert_indices,
+ GPU_pbvh_mesh_buffers_build(node->face_vert_indices,
bvh->mpoly, bvh->mloop, bvh->looptri,
bvh->verts,
node->prim_indices,
@@ -1110,42 +1116,44 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
break;
case PBVH_BMESH:
node->draw_buffers =
- GPU_build_bmesh_pbvh_buffers(bvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING);
+ GPU_pbvh_bmesh_buffers_build(bvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING);
break;
}
-
+
node->flag &= ~PBVH_RebuildDrawBuffers;
}
if (node->flag & PBVH_UpdateDrawBuffers) {
switch (bvh->type) {
case PBVH_GRIDS:
- GPU_update_grid_pbvh_buffers(node->draw_buffers,
- bvh->grids,
- bvh->grid_flag_mats,
- node->prim_indices,
- node->totprim,
- &bvh->gridkey,
- bvh->show_diffuse_color);
+ GPU_pbvh_grid_buffers_update(
+ node->draw_buffers,
+ bvh->grids,
+ bvh->grid_flag_mats,
+ node->prim_indices,
+ node->totprim,
+ &bvh->gridkey,
+ bvh->show_diffuse_color);
break;
case PBVH_FACES:
- GPU_update_mesh_pbvh_buffers(node->draw_buffers,
- bvh->verts,
- node->vert_indices,
- node->uniq_verts +
- node->face_verts,
- CustomData_get_layer(bvh->vdata,
- CD_PAINT_MASK),
- node->face_vert_indices,
- bvh->show_diffuse_color);
+ GPU_pbvh_mesh_buffers_update(
+ node->draw_buffers,
+ bvh->verts,
+ node->vert_indices,
+ node->uniq_verts +
+ node->face_verts,
+ CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
+ node->face_vert_indices,
+ bvh->show_diffuse_color);
break;
case PBVH_BMESH:
- GPU_update_bmesh_pbvh_buffers(node->draw_buffers,
- bvh->bm,
- node->bm_faces,
- node->bm_unique_verts,
- node->bm_other_verts,
- bvh->show_diffuse_color);
+ GPU_pbvh_bmesh_buffers_update(
+ node->draw_buffers,
+ bvh->bm,
+ node->bm_faces,
+ node->bm_unique_verts,
+ node->bm_other_verts,
+ bvh->show_diffuse_color);
break;
}
@@ -1154,17 +1162,17 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
}
}
-static void pbvh_draw_BB(PBVH *bvh)
+void BKE_pbvh_draw_BB(PBVH *bvh)
{
- GPU_init_draw_pbvh_BB();
+ GPU_pbvh_BB_draw_init();
for (int a = 0; a < bvh->totnode; a++) {
PBVHNode *node = &bvh->nodes[a];
- GPU_draw_pbvh_BB(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0));
+ GPU_pbvh_BB_draw(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0));
}
- GPU_end_draw_pbvh_BB();
+ GPU_pbvh_BB_draw_end();
}
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
@@ -1327,6 +1335,12 @@ void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key)
*key = bvh->gridkey;
}
+CCGDerivedMesh *BKE_pbvh_get_ccgdm(const PBVH *bvh)
+{
+ return bvh->ccgdm;
+}
+
+
BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
{
BLI_assert(bvh->type == PBVH_BMESH);
@@ -1525,14 +1539,16 @@ void BKE_pbvh_raycast(
bool ray_face_intersection_quad(
const float ray_start[3], const float ray_normal[3],
const float t0[3], const float t1[3], const float t2[3], const float t3[3],
- float *dist)
+ float *depth)
{
- float dist_test;
+ float depth_test;
- if ((isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t1, t2, &dist_test, NULL, 0.1f) && (dist_test < *dist)) ||
- (isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t2, t3, &dist_test, NULL, 0.1f) && (dist_test < *dist)))
+ if ((isect_ray_tri_epsilon_v3(
+ ray_start, ray_normal, t0, t1, t2, &depth_test, NULL, 0.1f) && (depth_test < *depth)) ||
+ (isect_ray_tri_epsilon_v3(
+ ray_start, ray_normal, t0, t2, t3, &depth_test, NULL, 0.1f) && (depth_test < *depth)))
{
- *dist = dist_test;
+ *depth = depth_test;
return true;
}
else {
@@ -1543,12 +1559,82 @@ bool ray_face_intersection_quad(
bool ray_face_intersection_tri(
const float ray_start[3], const float ray_normal[3],
const float t0[3], const float t1[3], const float t2[3],
- float *dist)
+ float *depth)
+{
+ float depth_test;
+
+ if ((isect_ray_tri_epsilon_v3(
+ ray_start, ray_normal, t0, t1, t2, &depth_test, NULL, 0.1f) && (depth_test < *depth)))
+ {
+ *depth = depth_test;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/* Take advantage of the fact we know this wont be an intersection.
+ * Just handle ray-tri edges. */
+static float dist_squared_ray_to_tri_v3_fast(
+ const float ray_origin[3], const float ray_direction[3],
+ const float v0[3], const float v1[3], const float v2[3],
+ float r_point[3], float *r_depth)
+{
+ const float *tri[3] = {v0, v1, v2};
+ float dist_sq_best = FLT_MAX;
+ for (int i = 0, j = 2; i < 3; j = i++) {
+ float point_test[3], depth_test = FLT_MAX;
+ const float dist_sq_test = dist_squared_ray_to_seg_v3(
+ ray_origin, ray_direction, tri[i], tri[j], point_test, &depth_test);
+ if (dist_sq_test < dist_sq_best || i == 0) {
+ copy_v3_v3(r_point, point_test);
+ *r_depth = depth_test;
+ dist_sq_best = dist_sq_test;
+ }
+ }
+ return dist_sq_best;
+}
+
+bool ray_face_nearest_quad(
+ const float ray_start[3], const float ray_normal[3],
+ const float t0[3], const float t1[3], const float t2[3], const float t3[3],
+ float *depth, float *dist_sq)
+{
+ float dist_sq_test;
+ float co[3], depth_test;
+
+ if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
+ ray_start, ray_normal, t0, t1, t2, co, &depth_test)) < *dist_sq))
+ {
+ *dist_sq = dist_sq_test;
+ *depth = depth_test;
+ if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
+ ray_start, ray_normal, t0, t2, t3, co, &depth_test)) < *dist_sq))
+ {
+ *dist_sq = dist_sq_test;
+ *depth = depth_test;
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool ray_face_nearest_tri(
+ const float ray_start[3], const float ray_normal[3],
+ const float t0[3], const float t1[3], const float t2[3],
+ float *depth, float *dist_sq)
{
- float dist_test;
+ float dist_sq_test;
+ float co[3], depth_test;
- if ((isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t1, t2, &dist_test, NULL, 0.1f) && (dist_test < *dist))) {
- *dist = dist_test;
+ if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
+ ray_start, ray_normal, t0, t1, t2, co, &depth_test)) < *dist_sq))
+ {
+ *dist_sq = dist_sq_test;
+ *depth = depth_test;
return true;
}
else {
@@ -1560,7 +1646,7 @@ static bool pbvh_faces_node_raycast(
PBVH *bvh, const PBVHNode *node,
float (*origco)[3],
const float ray_start[3], const float ray_normal[3],
- float *dist)
+ float *depth)
{
const MVert *vert = bvh->verts;
const MLoop *mloop = bvh->mloop;
@@ -1582,7 +1668,7 @@ static bool pbvh_faces_node_raycast(
origco[face_verts[0]],
origco[face_verts[1]],
origco[face_verts[2]],
- dist);
+ depth);
}
else {
/* intersect with current coordinates */
@@ -1591,7 +1677,7 @@ static bool pbvh_faces_node_raycast(
vert[mloop[lt->tri[0]].v].co,
vert[mloop[lt->tri[1]].v].co,
vert[mloop[lt->tri[2]].v].co,
- dist);
+ depth);
}
}
@@ -1602,7 +1688,7 @@ static bool pbvh_grids_node_raycast(
PBVH *bvh, PBVHNode *node,
float (*origco)[3],
const float ray_start[3], const float ray_normal[3],
- float *dist)
+ float *depth)
{
const int totgrid = node->totprim;
const int gridsize = bvh->gridkey.grid_size;
@@ -1632,7 +1718,7 @@ static bool pbvh_grids_node_raycast(
origco[y * gridsize + x + 1],
origco[(y + 1) * gridsize + x + 1],
origco[(y + 1) * gridsize + x],
- dist);
+ depth);
}
else {
hit |= ray_face_intersection_quad(
@@ -1641,7 +1727,7 @@ static bool pbvh_grids_node_raycast(
CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y),
CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1),
CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1),
- dist);
+ depth);
}
}
}
@@ -1656,7 +1742,7 @@ static bool pbvh_grids_node_raycast(
bool BKE_pbvh_node_raycast(
PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco,
const float ray_start[3], const float ray_normal[3],
- float *dist)
+ float *depth)
{
bool hit = false;
@@ -1667,16 +1753,16 @@ bool BKE_pbvh_node_raycast(
case PBVH_FACES:
hit |= pbvh_faces_node_raycast(
bvh, node, origco,
- ray_start, ray_normal, dist);
+ ray_start, ray_normal, depth);
break;
case PBVH_GRIDS:
hit |= pbvh_grids_node_raycast(
bvh, node, origco,
- ray_start, ray_normal, dist);
+ ray_start, ray_normal, depth);
break;
case PBVH_BMESH:
hit = pbvh_bmesh_node_raycast(
- node, ray_start, ray_normal, dist, use_origco);
+ node, ray_start, ray_normal, depth, use_origco);
break;
}
@@ -1727,6 +1813,176 @@ void BKE_pbvh_raycast_project_ray_root(
}
}
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
+ bool original;
+} FindNearestRayData;
+
+static bool nearest_to_ray_aabb_dist_sq(PBVHNode *node, void *data_v)
+{
+ FindNearestRayData *rcd = data_v;
+ const float *bb_min, *bb_max;
+
+ if (rcd->original) {
+ /* BKE_pbvh_node_get_original_BB */
+ bb_min = node->orig_vb.bmin;
+ bb_max = node->orig_vb.bmax;
+ }
+ else {
+ /* BKE_pbvh_node_get_BB */
+ bb_min = node->vb.bmin;
+ bb_max = node->vb.bmax;
+ }
+
+ float co_dummy[3], depth;
+ node->tmin = dist_squared_ray_to_aabb_v3(&rcd->dist_ray_to_aabb_precalc, bb_min, bb_max, co_dummy, &depth);
+ /* Ideally we would skip distances outside the range. */
+ return depth > 0.0f;
+}
+
+void BKE_pbvh_find_nearest_to_ray(
+ PBVH *bvh, BKE_pbvh_SearchNearestCallback cb, void *data,
+ const float ray_start[3], const float ray_normal[3],
+ bool original)
+{
+ FindNearestRayData ncd;
+
+ dist_squared_ray_to_aabb_v3_precalc(&ncd.dist_ray_to_aabb_precalc, ray_start, ray_normal);
+ ncd.original = original;
+
+ BKE_pbvh_search_callback_occluded(bvh, nearest_to_ray_aabb_dist_sq, &ncd, cb, data);
+}
+
+
+static bool pbvh_faces_node_nearest_to_ray(
+ PBVH *bvh, const PBVHNode *node,
+ float (*origco)[3],
+ const float ray_start[3], const float ray_normal[3],
+ float *depth, float *dist_sq)
+{
+ const MVert *vert = bvh->verts;
+ const MLoop *mloop = bvh->mloop;
+ const int *faces = node->prim_indices;
+ int i, totface = node->totprim;
+ bool hit = false;
+
+ for (i = 0; i < totface; ++i) {
+ const MLoopTri *lt = &bvh->looptri[faces[i]];
+ const int *face_verts = node->face_vert_indices[i];
+
+ if (paint_is_face_hidden(lt, vert, mloop))
+ continue;
+
+ if (origco) {
+ /* intersect with backuped original coordinates */
+ hit |= ray_face_nearest_tri(
+ ray_start, ray_normal,
+ origco[face_verts[0]],
+ origco[face_verts[1]],
+ origco[face_verts[2]],
+ depth, dist_sq);
+ }
+ else {
+ /* intersect with current coordinates */
+ hit |= ray_face_nearest_tri(
+ ray_start, ray_normal,
+ vert[mloop[lt->tri[0]].v].co,
+ vert[mloop[lt->tri[1]].v].co,
+ vert[mloop[lt->tri[2]].v].co,
+ depth, dist_sq);
+ }
+ }
+
+ return hit;
+}
+
+static bool pbvh_grids_node_nearest_to_ray(
+ PBVH *bvh, PBVHNode *node,
+ float (*origco)[3],
+ const float ray_start[3], const float ray_normal[3],
+ float *depth, float *dist_sq)
+{
+ const int totgrid = node->totprim;
+ const int gridsize = bvh->gridkey.grid_size;
+ bool hit = false;
+
+ for (int i = 0; i < totgrid; ++i) {
+ CCGElem *grid = bvh->grids[node->prim_indices[i]];
+ BLI_bitmap *gh;
+
+ if (!grid)
+ continue;
+
+ gh = bvh->grid_hidden[node->prim_indices[i]];
+
+ for (int y = 0; y < gridsize - 1; ++y) {
+ for (int x = 0; x < gridsize - 1; ++x) {
+ /* check if grid face is hidden */
+ if (gh) {
+ if (paint_is_grid_face_hidden(gh, gridsize, x, y))
+ continue;
+ }
+
+ if (origco) {
+ hit |= ray_face_nearest_quad(
+ ray_start, ray_normal,
+ origco[y * gridsize + x],
+ origco[y * gridsize + x + 1],
+ origco[(y + 1) * gridsize + x + 1],
+ origco[(y + 1) * gridsize + x],
+ depth, dist_sq);
+ }
+ else {
+ hit |= ray_face_nearest_quad(
+ ray_start, ray_normal,
+ CCG_grid_elem_co(&bvh->gridkey, grid, x, y),
+ CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y),
+ CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1),
+ CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1),
+ depth, dist_sq);
+ }
+ }
+ }
+
+ if (origco)
+ origco += gridsize * gridsize;
+ }
+
+ return hit;
+}
+
+bool BKE_pbvh_node_find_nearest_to_ray(
+ PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco,
+ const float ray_start[3], const float ray_normal[3],
+ float *depth, float *dist_sq)
+{
+ bool hit = false;
+
+ if (node->flag & PBVH_FullyHidden)
+ return false;
+
+ switch (bvh->type) {
+ case PBVH_FACES:
+ hit |= pbvh_faces_node_nearest_to_ray(
+ bvh, node, origco,
+ ray_start, ray_normal, depth, dist_sq);
+ break;
+ case PBVH_GRIDS:
+ hit |= pbvh_grids_node_nearest_to_ray(
+ bvh, node, origco,
+ ray_start, ray_normal, depth, dist_sq);
+ break;
+ case PBVH_BMESH:
+ hit = pbvh_bmesh_node_nearest_to_ray(
+ node, ray_start, ray_normal, depth, dist_sq, use_origco);
+ break;
+ }
+
+ return hit;
+}
+
typedef struct {
DMSetMaterial setMaterial;
bool wireframe;
@@ -1756,7 +2012,7 @@ void BKE_pbvh_node_draw(PBVHNode *node, void *data_v)
#endif
if (!(node->flag & PBVH_FullyHidden)) {
- GPU_draw_pbvh_buffers(node->draw_buffers,
+ GPU_pbvh_buffers_draw(node->draw_buffers,
data->setMaterial,
data->wireframe,
data->fast);
@@ -1858,7 +2114,7 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
}
if (G.debug_value == 14)
- pbvh_draw_BB(bvh);
+ BKE_pbvh_draw_BB(bvh);
}
void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces,
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index a821578db1a..187891e7210 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -352,7 +352,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
n->layer_disp = NULL;
if (n->draw_buffers) {
- GPU_free_pbvh_buffers(n->draw_buffers);
+ GPU_pbvh_buffers_free(n->draw_buffers);
n->draw_buffers = NULL;
}
n->flag &= ~PBVH_Leaf;
@@ -718,20 +718,24 @@ static void pbvh_bmesh_node_drop_orig(PBVHNode *node)
/****************************** EdgeQueue *****************************/
-typedef struct {
+struct EdgeQueue;
+
+typedef struct EdgeQueue {
Heap *heap;
const float *center;
+ float center_proj[3]; /* for when we use projected coords. */
float radius_squared;
float limit_len_squared;
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
float limit_len;
#endif
-#ifdef USE_EDGEQUEUE_FRONTFACE
+ bool (*edge_queue_tri_in_range)(const struct EdgeQueue *q, BMFace *f);
+
const float *view_normal;
+#ifdef USE_EDGEQUEUE_FRONTFACE
unsigned int use_view_normal : 1;
#endif
-
} EdgeQueue;
typedef struct {
@@ -785,7 +789,6 @@ static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f)
float c[3];
/* Get closest point in triangle to sphere center */
- // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3);
BM_face_as_array_vert_tri(f, v_tri);
closest_on_tri_to_point_v3(c, q->center, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
@@ -794,6 +797,25 @@ static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f)
return len_squared_v3v3(q->center, c) <= q->radius_squared;
}
+static bool edge_queue_tri_in_circle(const EdgeQueue *q, BMFace *f)
+{
+ BMVert *v_tri[3];
+ float c[3];
+ float tri_proj[3][3];
+
+ /* Get closest point in triangle to sphere center */
+ BM_face_as_array_vert_tri(f, v_tri);
+
+ project_plane_normalized_v3_v3v3(tri_proj[0], v_tri[0]->co, q->view_normal);
+ project_plane_normalized_v3_v3v3(tri_proj[1], v_tri[1]->co, q->view_normal);
+ project_plane_normalized_v3_v3v3(tri_proj[2], v_tri[2]->co, q->view_normal);
+
+ closest_on_tri_to_point_v3(c, q->center_proj, tri_proj[0], tri_proj[1], tri_proj[2]);
+
+ /* Check if triangle intersects the sphere */
+ return len_squared_v3v3(q->center_proj, c) <= q->radius_squared;
+}
+
/* Return true if the vertex mask is less than 1.0, false otherwise */
static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v)
{
@@ -929,7 +951,7 @@ static void long_edge_queue_face_add(
}
#endif
- if (edge_queue_tri_in_sphere(eq_ctx->q, f)) {
+ if (eq_ctx->q->edge_queue_tri_in_range(eq_ctx->q, f)) {
/* Check each edge of the face */
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter = l_first;
@@ -960,7 +982,7 @@ static void short_edge_queue_face_add(
}
#endif
- if (edge_queue_tri_in_sphere(eq_ctx->q, f)) {
+ if (eq_ctx->q->edge_queue_tri_in_range(eq_ctx->q, f)) {
BMLoop *l_iter;
BMLoop *l_first;
@@ -984,7 +1006,7 @@ static void short_edge_queue_face_add(
static void long_edge_queue_create(
EdgeQueueContext *eq_ctx,
PBVH *bvh, const float center[3], const float view_normal[3],
- float radius)
+ float radius, const bool use_frontface, const bool use_projected)
{
eq_ctx->q->heap = BLI_heap_new();
eq_ctx->q->center = center;
@@ -994,13 +1016,22 @@ static void long_edge_queue_create(
eq_ctx->q->limit_len = bvh->bm_max_edge_len;
#endif
-#ifdef USE_EDGEQUEUE_FRONTFACE
eq_ctx->q->view_normal = view_normal;
- eq_ctx->q->use_view_normal = (view_normal != NULL);
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ eq_ctx->q->use_view_normal = use_frontface;
#else
- UNUSED_VARS(view_normal);
+ UNUSED_VARS(use_frontface);
#endif
+ if (use_projected) {
+ eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_circle;
+ project_plane_normalized_v3_v3v3(eq_ctx->q->center_proj, center, view_normal);
+ }
+ else {
+ eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_sphere;
+ }
+
#ifdef USE_EDGEQUEUE_TAG_VERIFY
pbvh_bmesh_edge_tag_verify(bvh);
#endif
@@ -1037,7 +1068,7 @@ static void long_edge_queue_create(
static void short_edge_queue_create(
EdgeQueueContext *eq_ctx,
PBVH *bvh, const float center[3], const float view_normal[3],
- float radius)
+ float radius, const bool use_frontface, const bool use_projected)
{
eq_ctx->q->heap = BLI_heap_new();
eq_ctx->q->center = center;
@@ -1047,13 +1078,22 @@ static void short_edge_queue_create(
eq_ctx->q->limit_len = bvh->bm_min_edge_len;
#endif
-#ifdef USE_EDGEQUEUE_FRONTFACE
eq_ctx->q->view_normal = view_normal;
- eq_ctx->q->use_view_normal = (view_normal != NULL);
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ eq_ctx->q->use_view_normal = use_frontface;
#else
- UNUSED_VARS(view_normal);
+ UNUSED_VARS(use_frontface);
#endif
+ if (use_projected) {
+ eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_circle;
+ project_plane_normalized_v3_v3v3(eq_ctx->q->center_proj, center, view_normal);
+ }
+ else {
+ eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_sphere;
+ }
+
for (int n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
@@ -1466,7 +1506,7 @@ static bool pbvh_bmesh_collapse_short_edges(
bool pbvh_bmesh_node_raycast(
PBVHNode *node, const float ray_start[3],
- const float ray_normal[3], float *dist,
+ const float ray_normal[3], float *depth,
bool use_original)
{
bool hit = false;
@@ -1479,7 +1519,7 @@ bool pbvh_bmesh_node_raycast(
node->bm_orco[t[0]],
node->bm_orco[t[1]],
node->bm_orco[t[2]],
- dist);
+ depth);
}
}
else {
@@ -1498,7 +1538,7 @@ bool pbvh_bmesh_node_raycast(
v_tri[0]->co,
v_tri[1]->co,
v_tri[2]->co,
- dist);
+ depth);
}
}
}
@@ -1509,7 +1549,7 @@ bool pbvh_bmesh_node_raycast(
bool BKE_pbvh_bmesh_node_raycast_detail(
PBVHNode *node,
const float ray_start[3], const float ray_normal[3],
- float *dist, float *r_detail)
+ float *depth, float *r_detail)
{
if (node->flag & PBVH_FullyHidden)
return 0;
@@ -1531,7 +1571,7 @@ bool BKE_pbvh_bmesh_node_raycast_detail(
v_tri[0]->co,
v_tri[1]->co,
v_tri[2]->co,
- dist);
+ depth);
if (hit_local) {
f_hit = f;
@@ -1554,6 +1594,47 @@ bool BKE_pbvh_bmesh_node_raycast_detail(
return hit;
}
+bool pbvh_bmesh_node_nearest_to_ray(
+ PBVHNode *node, const float ray_start[3],
+ const float ray_normal[3], float *depth, float *dist_sq,
+ bool use_original)
+{
+ bool hit = false;
+
+ if (use_original && node->bm_tot_ortri) {
+ for (int i = 0; i < node->bm_tot_ortri; i++) {
+ const int *t = node->bm_ortri[i];
+ hit |= ray_face_nearest_tri(
+ ray_start, ray_normal,
+ node->bm_orco[t[0]],
+ node->bm_orco[t[1]],
+ node->bm_orco[t[2]],
+ depth, dist_sq);
+ }
+ }
+ else {
+ GSetIterator gs_iter;
+
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+
+ BLI_assert(f->len == 3);
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ BMVert *v_tri[3];
+
+ BM_face_as_array_vert_tri(f, v_tri);
+ hit |= ray_face_nearest_tri(
+ ray_start, ray_normal,
+ v_tri[0]->co,
+ v_tri[1]->co,
+ v_tri[2]->co,
+ depth, dist_sq);
+ }
+ }
+ }
+
+ return hit;
+}
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
{
@@ -1854,7 +1935,7 @@ void BKE_pbvh_build_bmesh(
bool BKE_pbvh_bmesh_update_topology(
PBVH *bvh, PBVHTopologyUpdateMode mode,
const float center[3], const float view_normal[3],
- float radius)
+ float radius, const bool use_frontface, const bool use_projected)
{
/* 2 is enough for edge faces - manifold edge */
BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
@@ -1877,7 +1958,7 @@ bool BKE_pbvh_bmesh_update_topology(
cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset,
};
- short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
+ short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
modified |= pbvh_bmesh_collapse_short_edges(
&eq_ctx, bvh, &deleted_faces);
BLI_heap_free(q.heap, NULL);
@@ -1892,7 +1973,7 @@ bool BKE_pbvh_bmesh_update_topology(
cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset,
};
- long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
+ long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
modified |= pbvh_bmesh_subdivide_long_edges(
&eq_ctx, bvh, &edge_loops);
BLI_heap_free(q.heap, NULL);
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 19d3b31bd31..e05a3068682 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -149,6 +149,8 @@ struct PBVH {
* objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer
* in an opaque pointer per pbvh. See T47637. */
struct GridCommonGPUBuffer *grid_common_gpu_buffer;
+ /* The ccgdm is required for CD_ORIGINDEX lookup in vertex paint + multires */
+ struct CCGDerivedMesh *ccgdm;
/* Only used during BVH build and update,
* don't need to remain valid after */
@@ -183,11 +185,21 @@ void pbvh_grow_nodes(PBVH *bvh, int totnode);
bool ray_face_intersection_quad(
const float ray_start[3], const float ray_normal[3],
const float *t0, const float *t1, const float *t2, const float *t3,
- float *r_dist);
+ float *depth);
bool ray_face_intersection_tri(
const float ray_start[3], const float ray_normal[3],
const float *t0, const float *t1, const float *t2,
- float *r_dist);
+ float *depth);
+
+bool ray_face_nearest_quad(
+ const float ray_start[3], const float ray_normal[3],
+ const float *t0, const float *t1, const float *t2, const float *t3,
+ float *r_depth, float *r_dist_sq);
+bool ray_face_nearest_tri(
+ const float ray_start[3], const float ray_normal[3],
+ const float *t0, const float *t1, const float *t2,
+ float *r_depth, float *r_dist_sq);
+
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
/* pbvh_bmesh.c */
@@ -195,6 +207,10 @@ bool pbvh_bmesh_node_raycast(
PBVHNode *node, const float ray_start[3],
const float ray_normal[3], float *dist,
bool use_original);
+bool pbvh_bmesh_node_nearest_to_ray(
+ PBVHNode *node, const float ray_start[3],
+ const float ray_normal[3], float *depth, float *dist_sq,
+ bool use_original);
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode);
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 6da69b129be..8bbf1a2e74b 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -3449,7 +3449,7 @@ void BKE_ptcache_free_list(ListBase *ptcaches)
}
}
-static PointCache *ptcache_copy(PointCache *cache, bool copy_data)
+static PointCache *ptcache_copy(PointCache *cache, const bool copy_data)
{
PointCache *ncache;
@@ -3492,14 +3492,15 @@ static PointCache *ptcache_copy(PointCache *cache, bool copy_data)
}
/* returns first point cache */
-PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, bool copy_data)
+PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, const int flag)
{
PointCache *cache = ptcaches_old->first;
BLI_listbase_clear(ptcaches_new);
- for (; cache; cache=cache->next)
- BLI_addtail(ptcaches_new, ptcache_copy(cache, copy_data));
+ for (; cache; cache=cache->next) {
+ BLI_addtail(ptcaches_new, ptcache_copy(cache, (flag & LIB_ID_COPY_CACHES) != 0));
+ }
return ptcaches_new->first;
}
@@ -3618,9 +3619,13 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
psys_get_pointcache_start_end(scene, pid->calldata, &cache->startframe, &cache->endframe);
}
- if ((cache->flag & PTCACHE_REDO_NEEDED || (cache->flag & PTCACHE_SIMULATION_VALID)==0) &&
- (render || bake))
- {
+ // XXX workaround for regression inroduced in ee3fadd, needs looking into
+ if (pid->type == PTCACHE_TYPE_RIGIDBODY) {
+ if ((cache->flag & PTCACHE_REDO_NEEDED || (cache->flag & PTCACHE_SIMULATION_VALID)==0) && (render || bake)) {
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+ }
+ }
+ else if (((cache->flag & PTCACHE_BAKED) == 0) && (render || bake)) {
BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
}
diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c
index dc4063b42ed..b163f623d21 100644
--- a/source/blender/blenkernel/intern/property.c
+++ b/source/blender/blenkernel/intern/property.c
@@ -65,7 +65,7 @@ void BKE_bproperty_free_list(ListBase *lb)
}
}
-bProperty *BKE_bproperty_copy(bProperty *prop)
+bProperty *BKE_bproperty_copy(const bProperty *prop)
{
bProperty *propn;
@@ -80,7 +80,7 @@ bProperty *BKE_bproperty_copy(bProperty *prop)
return propn;
}
-void BKE_bproperty_copy_list(ListBase *lbn, ListBase *lbo)
+void BKE_bproperty_copy_list(ListBase *lbn, const ListBase *lbo)
{
bProperty *prop, *propn;
BKE_bproperty_free_list(lbn); /* in case we are copying to an object with props */
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index ebf9f017731..03eb83376e7 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -46,6 +46,7 @@
# include "RBI_api.h"
#endif
+#include "DNA_ID.h"
#include "DNA_group_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -183,7 +184,7 @@ void BKE_rigidbody_free_constraint(Object *ob)
* be added to relevant groups later...
*/
-RigidBodyOb *BKE_rigidbody_copy_object(Object *ob)
+RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int UNUSED(flag))
{
RigidBodyOb *rboN = NULL;
@@ -203,7 +204,7 @@ RigidBodyOb *BKE_rigidbody_copy_object(Object *ob)
return rboN;
}
-RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob)
+RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(flag))
{
RigidBodyCon *rbcN = NULL;
@@ -222,13 +223,6 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob)
return rbcN;
}
-/* preserve relationships between constraints and rigid bodies after duplication */
-void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc)
-{
- ID_NEW(rbc->ob1);
- ID_NEW(rbc->ob2);
-}
-
/* ************************************** */
/* Setup Utilities - Validate Sim Instances */
@@ -297,8 +291,6 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
if (dm == NULL)
return NULL;
- DM_ensure_looptri(dm);
-
mvert = dm->getVertArray(dm);
totvert = dm->getNumVerts(dm);
looptri = dm->getLoopTriArray(dm);
@@ -530,8 +522,6 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
if (dm == NULL)
return;
- DM_ensure_looptri(dm);
-
mvert = dm->getVertArray(dm);
totvert = dm->getNumVerts(dm);
lt = dm->getLoopTriArray(dm);
@@ -615,8 +605,6 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3])
if (dm == NULL)
return;
- DM_ensure_looptri(dm);
-
mvert = dm->getVertArray(dm);
totvert = dm->getNumVerts(dm);
looptri = dm->getLoopTriArray(dm);
@@ -828,7 +816,7 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z);
RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint);
- /* fall-through */
+ ATTR_FALLTHROUGH;
case RBC_TYPE_6DOF:
if (rbc->type == RBC_TYPE_6DOF) /* a litte awkward but avoids duplicate code for limits */
rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2);
@@ -951,46 +939,45 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
return rbw;
}
-RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw)
+RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag)
{
- RigidBodyWorld *rbwn = MEM_dupallocN(rbw);
+ RigidBodyWorld *rbw_copy = MEM_dupallocN(rbw);
- if (rbw->effector_weights)
- rbwn->effector_weights = MEM_dupallocN(rbw->effector_weights);
- if (rbwn->group)
- id_us_plus(&rbwn->group->id);
- if (rbwn->constraints)
- id_us_plus(&rbwn->constraints->id);
+ if (rbw->effector_weights) {
+ rbw_copy->effector_weights = MEM_dupallocN(rbw->effector_weights);
+ }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)rbw_copy->group);
+ id_us_plus((ID *)rbw_copy->constraints);
+ }
- rbwn->pointcache = BKE_ptcache_copy_list(&rbwn->ptcaches, &rbw->ptcaches, false);
+ /* XXX Never copy caches here? */
+ rbw_copy->pointcache = BKE_ptcache_copy_list(&rbw_copy->ptcaches, &rbw->ptcaches, flag & ~LIB_ID_COPY_CACHES);
- rbwn->objects = NULL;
- rbwn->physics_world = NULL;
- rbwn->numbodies = 0;
+ rbw_copy->objects = NULL;
+ rbw_copy->physics_world = NULL;
+ rbw_copy->numbodies = 0;
- return rbwn;
+ return rbw_copy;
}
void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw)
{
- if (rbw->group && rbw->group->id.newid)
- rbw->group = (Group *)rbw->group->id.newid;
- if (rbw->constraints && rbw->constraints->id.newid)
- rbw->constraints = (Group *)rbw->constraints->id.newid;
- if (rbw->effector_weights->group && rbw->effector_weights->group->id.newid)
- rbw->effector_weights->group = (Group *)rbw->effector_weights->group->id.newid;
+ ID_NEW_REMAP(rbw->group);
+ ID_NEW_REMAP(rbw->constraints);
+ ID_NEW_REMAP(rbw->effector_weights->group);
}
void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata)
{
- func(rbw, (ID **)&rbw->group, userdata, IDWALK_NOP);
- func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_NOP);
- func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_NOP);
+ func(rbw, (ID **)&rbw->group, userdata, IDWALK_CB_NOP);
+ func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_CB_NOP);
+ func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_CB_NOP);
if (rbw->objects) {
int i;
for (i = 0; i < rbw->numbodies; i++) {
- func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_NOP);
+ func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_CB_NOP);
}
}
}
@@ -1495,24 +1482,60 @@ void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle)
{
RigidBodyOb *rbo = ob->rigidbody_object;
+ bool correct_delta = !(rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE);
/* return rigid body and object to their initial states */
copy_v3_v3(rbo->pos, ob->loc);
copy_v3_v3(ob->loc, loc);
+ if (correct_delta) {
+ add_v3_v3(rbo->pos, ob->dloc);
+ }
+
if (ob->rotmode > 0) {
- eulO_to_quat(rbo->orn, ob->rot, ob->rotmode);
+ float qt[4];
+ eulO_to_quat(qt, ob->rot, ob->rotmode);
+
+ if (correct_delta) {
+ float dquat[4];
+ eulO_to_quat(dquat, ob->drot, ob->rotmode);
+
+ mul_qt_qtqt(rbo->orn, dquat, qt);
+ }
+ else {
+ copy_qt_qt(rbo->orn, qt);
+ }
+
copy_v3_v3(ob->rot, rot);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_quat(rbo->orn, ob->rotAxis, ob->rotAngle);
+ float qt[4];
+ axis_angle_to_quat(qt, ob->rotAxis, ob->rotAngle);
+
+ if (correct_delta) {
+ float dquat[4];
+ axis_angle_to_quat(dquat, ob->drotAxis, ob->drotAngle);
+
+ mul_qt_qtqt(rbo->orn, dquat, qt);
+ }
+ else {
+ copy_qt_qt(rbo->orn, qt);
+ }
+
copy_v3_v3(ob->rotAxis, rotAxis);
ob->rotAngle = rotAngle;
}
else {
- copy_qt_qt(rbo->orn, ob->quat);
+ if (correct_delta) {
+ mul_qt_qtqt(rbo->orn, ob->dquat, ob->quat);
+ }
+ else {
+ copy_qt_qt(rbo->orn, ob->quat);
+ }
+
copy_qt_qt(ob->quat, quat);
}
+
if (rbo->physics_object) {
/* allow passive objects to return to original transform */
if (rbo->type == RBO_TYPE_PASSIVE)
@@ -1524,8 +1547,9 @@ void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], flo
void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
{
- if (rbw)
+ if (rbw) {
rbw->pointcache->flag |= PTCACHE_OUTDATED;
+ }
}
/* ------------------ */
@@ -1591,7 +1615,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
// RB_TODO deal with interpolated, old and baked results
bool can_simulate = (ctime == rbw->ltime + 1) && !(cache->flag & PTCACHE_BAKED);
- if (BKE_ptcache_read(&pid, ctime, can_simulate)) {
+ if (BKE_ptcache_read(&pid, ctime, can_simulate) == PTCACHE_READ_EXACT) {
BKE_ptcache_validate(cache, (int)ctime);
rbw->ltime = ctime;
return;
@@ -1631,14 +1655,13 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
# pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
-struct RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) { return NULL; }
-struct RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) { return NULL; }
-void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) {}
+struct RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag) { return NULL; }
+struct RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int flag) { return NULL; }
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) {}
void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) { if (r_vol) *r_vol = 0.0f; }
void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) { zero_v3(r_center); }
struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { return NULL; }
-struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw) { return NULL; }
+struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag) { return NULL; }
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw) {}
void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) {}
struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { return NULL; }
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index c7f406089d9..fb81ed4d47f 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -72,7 +72,7 @@ void free_sensors(ListBase *lb)
}
}
-bSensor *copy_sensor(bSensor *sens)
+bSensor *copy_sensor(bSensor *sens, const int UNUSED(flag))
{
bSensor *sensn;
@@ -87,14 +87,14 @@ bSensor *copy_sensor(bSensor *sens)
return sensn;
}
-void copy_sensors(ListBase *lbn, ListBase *lbo)
+void copy_sensors(ListBase *lbn, const ListBase *lbo, const int flag)
{
bSensor *sens, *sensn;
lbn->first= lbn->last= NULL;
sens= lbo->first;
while (sens) {
- sensn= copy_sensor(sens);
+ sensn= copy_sensor(sens, flag);
BLI_addtail(lbn, sensn);
sens= sens->next;
}
@@ -234,7 +234,7 @@ void free_controllers(ListBase *lb)
}
}
-bController *copy_controller(bController *cont)
+bController *copy_controller(bController *cont, const int UNUSED(flag))
{
bController *contn;
@@ -251,14 +251,14 @@ bController *copy_controller(bController *cont)
return contn;
}
-void copy_controllers(ListBase *lbn, ListBase *lbo)
+void copy_controllers(ListBase *lbn, const ListBase *lbo, const int flag)
{
bController *cont, *contn;
lbn->first= lbn->last= NULL;
cont= lbo->first;
while (cont) {
- contn= copy_controller(cont);
+ contn= copy_controller(cont, flag);
BLI_addtail(lbn, contn);
cont= cont->next;
}
@@ -359,7 +359,7 @@ void free_actuators(ListBase *lb)
}
}
-bActuator *copy_actuator(bActuator *act)
+bActuator *copy_actuator(bActuator *act, const int flag)
{
bActuator *actn;
@@ -374,29 +374,31 @@ bActuator *copy_actuator(bActuator *act)
case ACT_SHAPEACTION:
{
bActionActuator *aa = (bActionActuator *)act->data;
- if (aa->act)
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
id_us_plus((ID *)aa->act);
+ }
break;
}
case ACT_SOUND:
{
bSoundActuator *sa = (bSoundActuator *)act->data;
- if (sa->sound)
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
id_us_plus((ID *)sa->sound);
+ }
break;
}
}
return actn;
}
-void copy_actuators(ListBase *lbn, ListBase *lbo)
+void copy_actuators(ListBase *lbn, const ListBase *lbo, const int flag)
{
bActuator *act, *actn;
lbn->first= lbn->last= NULL;
act= lbo->first;
while (act) {
- actn= copy_actuator(act);
+ actn= copy_actuator(act, flag);
BLI_addtail(lbn, actn);
act= act->next;
}
@@ -602,41 +604,41 @@ void set_sca_new_poins_ob(Object *ob)
if (act->flag & ACT_NEW) {
if (act->type==ACT_EDIT_OBJECT) {
bEditObjectActuator *eoa= act->data;
- ID_NEW(eoa->ob);
+ ID_NEW_REMAP(eoa->ob);
}
else if (act->type==ACT_SCENE) {
bSceneActuator *sca= act->data;
- ID_NEW(sca->camera);
+ ID_NEW_REMAP(sca->camera);
}
else if (act->type==ACT_CAMERA) {
bCameraActuator *ca= act->data;
- ID_NEW(ca->ob);
+ ID_NEW_REMAP(ca->ob);
}
else if (act->type==ACT_OBJECT) {
bObjectActuator *oa= act->data;
- ID_NEW(oa->reference);
+ ID_NEW_REMAP(oa->reference);
}
else if (act->type==ACT_MESSAGE) {
bMessageActuator *ma= act->data;
- ID_NEW(ma->toObject);
+ ID_NEW_REMAP(ma->toObject);
}
else if (act->type==ACT_PARENT) {
bParentActuator *para = act->data;
- ID_NEW(para->ob);
+ ID_NEW_REMAP(para->ob);
}
else if (act->type==ACT_ARMATURE) {
bArmatureActuator *aa = act->data;
- ID_NEW(aa->target);
- ID_NEW(aa->subtarget);
+ ID_NEW_REMAP(aa->target);
+ ID_NEW_REMAP(aa->subtarget);
}
else if (act->type==ACT_PROPERTY) {
bPropertyActuator *pa= act->data;
- ID_NEW(pa->ob);
+ ID_NEW_REMAP(pa->ob);
}
else if (act->type==ACT_STEERING) {
bSteeringActuator *sta = act->data;
- ID_NEW(sta->navmesh);
- ID_NEW(sta->target);
+ ID_NEW_REMAP(sta->navmesh);
+ ID_NEW_REMAP(sta->target);
}
}
act= act->next;
@@ -783,11 +785,11 @@ void BKE_sca_logic_links_remap(Main *bmain, Object *ob_old, Object *ob_new)
* Handle the copying of logic data into a new object, including internal logic links update.
* External links (links between logic bricks of different objects) must be handled separately.
*/
-void BKE_sca_logic_copy(Object *ob_new, Object *ob)
+void BKE_sca_logic_copy(Object *ob_new, const Object *ob, const int flag)
{
- copy_sensors(&ob_new->sensors, &ob->sensors);
- copy_controllers(&ob_new->controllers, &ob->controllers);
- copy_actuators(&ob_new->actuators, &ob->actuators);
+ copy_sensors(&ob_new->sensors, &ob->sensors, flag);
+ copy_controllers(&ob_new->controllers, &ob->controllers, flag);
+ copy_actuators(&ob_new->actuators, &ob->actuators, flag);
for (bSensor *sens = ob_new->sensors.first; sens; sens = sens->next) {
if (sens->flag & SENS_NEW) {
@@ -992,19 +994,19 @@ void BKE_sca_sensors_id_loop(ListBase *senslist, SCASensorIDFunc func, void *use
bSensor *sensor;
for (sensor = senslist->first; sensor; sensor = sensor->next) {
- func(sensor, (ID **)&sensor->ob, userdata, IDWALK_NOP);
+ func(sensor, (ID **)&sensor->ob, userdata, IDWALK_CB_NOP);
switch (sensor->type) {
case SENS_TOUCH: /* DEPRECATED */
{
bTouchSensor *ts = sensor->data;
- func(sensor, (ID **)&ts->ma, userdata, IDWALK_NOP);
+ func(sensor, (ID **)&ts->ma, userdata, IDWALK_CB_NOP);
break;
}
case SENS_MESSAGE:
{
bMessageSensor *ms = sensor->data;
- func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_NOP);
+ func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_CB_NOP);
break;
}
case SENS_ALWAYS:
@@ -1035,7 +1037,7 @@ void BKE_sca_controllers_id_loop(ListBase *contlist, SCAControllerIDFunc func, v
case CONT_PYTHON:
{
bPythonCont *pc = controller->data;
- func(controller, (ID **)&pc->text, userdata, IDWALK_NOP);
+ func(controller, (ID **)&pc->text, userdata, IDWALK_CB_NOP);
break;
}
case CONT_LOGIC_AND:
@@ -1056,89 +1058,89 @@ void BKE_sca_actuators_id_loop(ListBase *actlist, SCAActuatorIDFunc func, void *
bActuator *actuator;
for (actuator = actlist->first; actuator; actuator = actuator->next) {
- func(actuator, (ID **)&actuator->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&actuator->ob, userdata, IDWALK_CB_NOP);
switch (actuator->type) {
case ACT_ADD_OBJECT: /* DEPRECATED */
{
bAddObjectActuator *aoa = actuator->data;
- func(actuator, (ID **)&aoa->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&aoa->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_ACTION:
{
bActionActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->act, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&aa->act, userdata, IDWALK_CB_NOP);
break;
}
case ACT_SOUND:
{
bSoundActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->sound, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&sa->sound, userdata, IDWALK_CB_NOP);
break;
}
case ACT_EDIT_OBJECT:
{
bEditObjectActuator *eoa = actuator->data;
- func(actuator, (ID **)&eoa->ob, userdata, IDWALK_NOP);
- func(actuator, (ID **)&eoa->me, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&eoa->ob, userdata, IDWALK_CB_NOP);
+ func(actuator, (ID **)&eoa->me, userdata, IDWALK_CB_NOP);
break;
}
case ACT_SCENE:
{
bSceneActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->scene, userdata, IDWALK_NOP);
- func(actuator, (ID **)&sa->camera, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&sa->scene, userdata, IDWALK_CB_NOP);
+ func(actuator, (ID **)&sa->camera, userdata, IDWALK_CB_NOP);
break;
}
case ACT_PROPERTY:
{
bPropertyActuator *pa = actuator->data;
- func(actuator, (ID **)&pa->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_OBJECT:
{
bObjectActuator *oa = actuator->data;
- func(actuator, (ID **)&oa->reference, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&oa->reference, userdata, IDWALK_CB_NOP);
break;
}
case ACT_CAMERA:
{
bCameraActuator *ca = actuator->data;
- func(actuator, (ID **)&ca->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&ca->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_MESSAGE:
{
bMessageActuator *ma = actuator->data;
- func(actuator, (ID **)&ma->toObject, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&ma->toObject, userdata, IDWALK_CB_NOP);
break;
}
case ACT_2DFILTER:
{
bTwoDFilterActuator *tdfa = actuator->data;
- func(actuator, (ID **)&tdfa->text, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&tdfa->text, userdata, IDWALK_CB_NOP);
break;
}
case ACT_PARENT:
{
bParentActuator *pa = actuator->data;
- func(actuator, (ID **)&pa->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_ARMATURE:
{
bArmatureActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->target, userdata, IDWALK_NOP);
- func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&aa->target, userdata, IDWALK_CB_NOP);
+ func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_CB_NOP);
break;
}
case ACT_STEERING:
{
bSteeringActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->target, userdata, IDWALK_NOP);
- func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&sa->target, userdata, IDWALK_CB_NOP);
+ func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_CB_NOP);
break;
}
/* Note: some types seems to be non-implemented? ACT_LAMP, ACT_MATERIAL... */
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 6e1f11cb526..4526477cad9 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -56,6 +56,7 @@
#include "BLI_utildefines.h"
#include "BLI_callbacks.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLI_task.h"
@@ -78,6 +79,7 @@
#include "BKE_idprop.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_mask.h"
@@ -123,17 +125,6 @@ void free_avicodecdata(AviCodecData *acd)
}
}
-void free_qtcodecdata(QuicktimeCodecData *qcd)
-{
- if (qcd) {
- if (qcd->cdParms) {
- MEM_freeN(qcd->cdParms);
- qcd->cdParms = NULL;
- qcd->cdSize = 0;
- }
- }
-}
-
static void remove_sequencer_fcurves(Scene *sce)
{
AnimData *adt = BKE_animdata_from_id(&sce->id);
@@ -152,209 +143,294 @@ static void remove_sequencer_fcurves(Scene *sce)
}
}
-Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
-{
- Scene *scen;
- SceneRenderLayer *srl, *new_srl;
- FreestyleLineSet *lineset;
- ToolSettings *ts;
- Base *base, *obase;
-
- if (type == SCE_COPY_EMPTY) {
- ListBase rl, rv;
- scen = BKE_scene_add(bmain, sce->id.name + 2);
-
- rl = scen->r.layers;
- rv = scen->r.views;
- curvemapping_free_data(&scen->r.mblur_shutter_curve);
- scen->r = sce->r;
- scen->r.layers = rl;
- scen->r.actlay = 0;
- scen->r.views = rv;
- scen->unit = sce->unit;
- scen->physics_settings = sce->physics_settings;
- scen->gm = sce->gm;
- scen->audio = sce->audio;
-
- if (sce->id.properties)
- scen->id.properties = IDP_CopyProperty(sce->id.properties);
-
- MEM_freeN(scen->toolsettings);
- BKE_sound_destroy_scene(scen);
- }
- else {
- scen = BKE_libblock_copy(bmain, &sce->id);
- BLI_duplicatelist(&(scen->base), &(sce->base));
-
- BKE_main_id_clear_newpoins(bmain);
-
- id_us_plus((ID *)scen->world);
- id_us_plus((ID *)scen->set);
- /* id_us_plus((ID *)scen->gm.dome.warptext); */ /* XXX Not refcounted? see readfile.c */
-
- scen->ed = NULL;
- scen->theDag = NULL;
- scen->depsgraph = NULL;
- scen->obedit = NULL;
- scen->stats = NULL;
- scen->fps_info = NULL;
-
- if (sce->rigidbody_world)
- scen->rigidbody_world = BKE_rigidbody_world_copy(sce->rigidbody_world);
-
- BLI_duplicatelist(&(scen->markers), &(sce->markers));
- BLI_duplicatelist(&(scen->transform_spaces), &(sce->transform_spaces));
- BLI_duplicatelist(&(scen->r.layers), &(sce->r.layers));
- BLI_duplicatelist(&(scen->r.views), &(sce->r.views));
- BKE_keyingsets_copy(&(scen->keyingsets), &(sce->keyingsets));
-
- if (sce->nodetree) {
- /* ID's are managed on both copy and switch */
- scen->nodetree = ntreeCopyTree(bmain, sce->nodetree);
- ntreeSwitchID(scen->nodetree, &sce->id, &scen->id);
+/**
+ * Only copy internal data of Scene ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, const int flag)
+{
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+
+ sce_dst->ed = NULL;
+ sce_dst->theDag = NULL;
+ sce_dst->depsgraph = NULL;
+ sce_dst->obedit = NULL;
+ sce_dst->stats = NULL;
+ sce_dst->fps_info = NULL;
+
+ BLI_duplicatelist(&(sce_dst->base), &(sce_src->base));
+ for (Base *base_dst = sce_dst->base.first, *base_src = sce_src->base.first;
+ base_dst;
+ base_dst = base_dst->next, base_src = base_src->next)
+ {
+ if (base_src == sce_src->basact) {
+ sce_dst->basact = base_dst;
}
+ }
- obase = sce->base.first;
- base = scen->base.first;
- while (base) {
- id_us_plus(&base->object->id);
- if (obase == sce->basact) scen->basact = base;
-
- obase = obase->next;
- base = base->next;
- }
+ BLI_duplicatelist(&(sce_dst->markers), &(sce_src->markers));
+ BLI_duplicatelist(&(sce_dst->transform_spaces), &(sce_src->transform_spaces));
+ BLI_duplicatelist(&(sce_dst->r.layers), &(sce_src->r.layers));
+ BLI_duplicatelist(&(sce_dst->r.views), &(sce_src->r.views));
+ BKE_keyingsets_copy(&(sce_dst->keyingsets), &(sce_src->keyingsets));
- /* copy action and remove animation used by sequencer */
- BKE_animdata_copy_id_action(&scen->id);
+ if (sce_src->nodetree) {
+ BKE_id_copy_ex(bmain, (ID *)sce_src->nodetree, (ID **)&sce_dst->nodetree, flag, false);
+ BKE_libblock_relink_ex(bmain, sce_dst->nodetree, (void *)(&sce_src->id), &sce_dst->id, false);
+ }
- if (type != SCE_COPY_FULL)
- remove_sequencer_fcurves(scen);
+ if (sce_src->rigidbody_world) {
+ sce_dst->rigidbody_world = BKE_rigidbody_world_copy(sce_src->rigidbody_world, flag_subdata);
+ }
- /* copy Freestyle settings */
- new_srl = scen->r.layers.first;
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- BKE_freestyle_config_copy(&new_srl->freestyleConfig, &srl->freestyleConfig);
- if (type == SCE_COPY_FULL) {
- for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
- if (lineset->linestyle) {
- id_us_plus((ID *)lineset->linestyle);
- lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle);
- }
- }
- }
- new_srl = new_srl->next;
+ /* copy Freestyle settings */
+ for (SceneRenderLayer *srl_dst = sce_dst->r.layers.first, *srl_src = sce_src->r.layers.first;
+ srl_src;
+ srl_dst = srl_dst->next, srl_src = srl_src->next)
+ {
+ if (srl_dst->prop != NULL) {
+ srl_dst->prop = IDP_CopyProperty_ex(srl_dst->prop, flag_subdata);
}
+ BKE_freestyle_config_copy(&srl_dst->freestyleConfig, &srl_src->freestyleConfig, flag_subdata);
}
/* copy color management settings */
- BKE_color_managed_display_settings_copy(&scen->display_settings, &sce->display_settings);
- BKE_color_managed_view_settings_copy(&scen->view_settings, &sce->view_settings);
- BKE_color_managed_colorspace_settings_copy(&scen->sequencer_colorspace_settings, &sce->sequencer_colorspace_settings);
+ BKE_color_managed_display_settings_copy(&sce_dst->display_settings, &sce_src->display_settings);
+ BKE_color_managed_view_settings_copy(&sce_dst->view_settings, &sce_src->view_settings);
+ BKE_color_managed_colorspace_settings_copy(&sce_dst->sequencer_colorspace_settings, &sce_src->sequencer_colorspace_settings);
- BKE_color_managed_display_settings_copy(&scen->r.im_format.display_settings, &sce->r.im_format.display_settings);
- BKE_color_managed_view_settings_copy(&scen->r.im_format.view_settings, &sce->r.im_format.view_settings);
+ BKE_color_managed_display_settings_copy(&sce_dst->r.im_format.display_settings, &sce_src->r.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&sce_dst->r.im_format.view_settings, &sce_src->r.im_format.view_settings);
- BKE_color_managed_display_settings_copy(&scen->r.bake.im_format.display_settings, &sce->r.bake.im_format.display_settings);
- BKE_color_managed_view_settings_copy(&scen->r.bake.im_format.view_settings, &sce->r.bake.im_format.view_settings);
+ BKE_color_managed_display_settings_copy(&sce_dst->r.bake.im_format.display_settings, &sce_src->r.bake.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&sce_dst->r.bake.im_format.view_settings, &sce_src->r.bake.im_format.view_settings);
- curvemapping_copy_data(&scen->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve);
+ curvemapping_copy_data(&sce_dst->r.mblur_shutter_curve, &sce_src->r.mblur_shutter_curve);
/* tool settings */
- scen->toolsettings = MEM_dupallocN(sce->toolsettings);
-
- ts = scen->toolsettings;
- if (ts) {
+ if (sce_dst->toolsettings != NULL) {
+ ToolSettings *ts = sce_dst->toolsettings = MEM_dupallocN(sce_dst->toolsettings);
if (ts->vpaint) {
ts->vpaint = MEM_dupallocN(ts->vpaint);
- ts->vpaint->paintcursor = NULL;
- ts->vpaint->vpaint_prev = NULL;
- ts->vpaint->wpaint_prev = NULL;
- BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint);
+ BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag_subdata);
}
if (ts->wpaint) {
ts->wpaint = MEM_dupallocN(ts->wpaint);
- ts->wpaint->paintcursor = NULL;
- ts->wpaint->vpaint_prev = NULL;
- ts->wpaint->wpaint_prev = NULL;
- BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint);
+ BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag_subdata);
}
if (ts->sculpt) {
ts->sculpt = MEM_dupallocN(ts->sculpt);
- BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint);
+ BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag_subdata);
+ }
+ if (ts->uvsculpt) {
+ ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
+ BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag_subdata);
}
- BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint);
+ BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag_subdata);
ts->imapaint.paintcursor = NULL;
- id_us_plus((ID *)ts->imapaint.stencil);
ts->particle.paintcursor = NULL;
+ ts->particle.scene = NULL;
+ ts->particle.object = NULL;
+
/* duplicate Grease Pencil Drawing Brushes */
BLI_listbase_clear(&ts->gp_brushes);
- for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
+ for (bGPDbrush *brush = sce_src->toolsettings->gp_brushes.first; brush; brush = brush->next) {
bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
BLI_addtail(&ts->gp_brushes, newbrush);
}
+ /* duplicate Grease Pencil interpolation curve */
+ ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
}
-
+
/* make a private copy of the avicodecdata */
- if (sce->r.avicodecdata) {
- scen->r.avicodecdata = MEM_dupallocN(sce->r.avicodecdata);
- scen->r.avicodecdata->lpFormat = MEM_dupallocN(scen->r.avicodecdata->lpFormat);
- scen->r.avicodecdata->lpParms = MEM_dupallocN(scen->r.avicodecdata->lpParms);
- }
-
- /* make a private copy of the qtcodecdata */
- if (sce->r.qtcodecdata) {
- scen->r.qtcodecdata = MEM_dupallocN(sce->r.qtcodecdata);
- scen->r.qtcodecdata->cdParms = MEM_dupallocN(scen->r.qtcodecdata->cdParms);
+ if (sce_src->r.avicodecdata) {
+ sce_dst->r.avicodecdata = MEM_dupallocN(sce_src->r.avicodecdata);
+ sce_dst->r.avicodecdata->lpFormat = MEM_dupallocN(sce_dst->r.avicodecdata->lpFormat);
+ sce_dst->r.avicodecdata->lpParms = MEM_dupallocN(sce_dst->r.avicodecdata->lpParms);
}
-
- if (sce->r.ffcodecdata.properties) { /* intentionally check scen not sce. */
- scen->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties);
+
+ if (sce_src->r.ffcodecdata.properties) { /* intentionally check sce_dst not sce_src. */ /* XXX ??? comment outdated... */
+ sce_dst->r.ffcodecdata.properties = IDP_CopyProperty_ex(sce_src->r.ffcodecdata.properties, flag_subdata);
}
- /* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations
- * are done outside of blenkernel with ED_objects_single_users! */
+ /* before scene copy */
+ BKE_sound_create_scene(sce_dst);
- /* camera */
- if (type == SCE_COPY_LINK_DATA || type == SCE_COPY_FULL) {
- ID_NEW(scen->camera);
+ /* Copy sequencer, this is local data! */
+ if (sce_src->ed) {
+ sce_dst->ed = MEM_callocN(sizeof(*sce_dst->ed), __func__);
+ sce_dst->ed->seqbasep = &sce_dst->ed->seqbase;
+ BKE_sequence_base_dupli_recursive(
+ sce_src, sce_dst, &sce_dst->ed->seqbase, &sce_src->ed->seqbase, SEQ_DUPE_ALL, flag_subdata);
}
-
- /* before scene copy */
- BKE_sound_create_scene(scen);
- /* world */
- if (type == SCE_COPY_FULL) {
- if (scen->world) {
- id_us_plus((ID *)scen->world);
- scen->world = BKE_world_copy(bmain, scen->world);
- BKE_animdata_copy_id_action((ID *)scen->world);
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&sce_dst->id, &sce_src->id);
+ }
+ else {
+ sce_dst->preview = NULL;
+ }
+}
+
+Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
+{
+ Scene *sce_copy;
+
+ /* TODO this should/could most likely be replaced by call to more generic code at some point...
+ * But for now, let's keep it well isolated here. */
+ if (type == SCE_COPY_EMPTY) {
+ ToolSettings *ts;
+ ListBase rl, rv;
+
+ sce_copy = BKE_scene_add(bmain, sce->id.name + 2);
+
+ rl = sce_copy->r.layers;
+ rv = sce_copy->r.views;
+ curvemapping_free_data(&sce_copy->r.mblur_shutter_curve);
+ sce_copy->r = sce->r;
+ sce_copy->r.layers = rl;
+ sce_copy->r.actlay = 0;
+ sce_copy->r.views = rv;
+ sce_copy->unit = sce->unit;
+ sce_copy->physics_settings = sce->physics_settings;
+ sce_copy->gm = sce->gm;
+ sce_copy->audio = sce->audio;
+
+ if (sce->id.properties)
+ sce_copy->id.properties = IDP_CopyProperty(sce->id.properties);
+
+ MEM_freeN(sce_copy->toolsettings);
+ BKE_sound_destroy_scene(sce_copy);
+
+ /* copy color management settings */
+ BKE_color_managed_display_settings_copy(&sce_copy->display_settings, &sce->display_settings);
+ BKE_color_managed_view_settings_copy(&sce_copy->view_settings, &sce->view_settings);
+ BKE_color_managed_colorspace_settings_copy(&sce_copy->sequencer_colorspace_settings, &sce->sequencer_colorspace_settings);
+
+ BKE_color_managed_display_settings_copy(&sce_copy->r.im_format.display_settings, &sce->r.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&sce_copy->r.im_format.view_settings, &sce->r.im_format.view_settings);
+
+ BKE_color_managed_display_settings_copy(&sce_copy->r.bake.im_format.display_settings, &sce->r.bake.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&sce_copy->r.bake.im_format.view_settings, &sce->r.bake.im_format.view_settings);
+
+ curvemapping_copy_data(&sce_copy->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve);
+
+ /* tool settings */
+ sce_copy->toolsettings = MEM_dupallocN(sce->toolsettings);
+
+ ts = sce_copy->toolsettings;
+ if (ts) {
+ if (ts->vpaint) {
+ ts->vpaint = MEM_dupallocN(ts->vpaint);
+ BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, 0);
+ }
+ if (ts->wpaint) {
+ ts->wpaint = MEM_dupallocN(ts->wpaint);
+ BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, 0);
+ }
+ if (ts->sculpt) {
+ ts->sculpt = MEM_dupallocN(ts->sculpt);
+ BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, 0);
+ }
+ if (ts->uvsculpt) {
+ ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
+ BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, 0);
+ }
+
+ BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, 0);
+ ts->imapaint.paintcursor = NULL;
+ id_us_plus((ID *)ts->imapaint.stencil);
+ id_us_plus((ID *)ts->imapaint.clone);
+ id_us_plus((ID *)ts->imapaint.canvas);
+ ts->particle.paintcursor = NULL;
+ ts->particle.scene = NULL;
+ ts->particle.object = NULL;
+
+ /* duplicate Grease Pencil Drawing Brushes */
+ BLI_listbase_clear(&ts->gp_brushes);
+ for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
+ bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
+ BLI_addtail(&ts->gp_brushes, newbrush);
+ }
+
+ /* duplicate Grease Pencil interpolation curve */
+ ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
+ }
+
+ /* make a private copy of the avicodecdata */
+ if (sce->r.avicodecdata) {
+ sce_copy->r.avicodecdata = MEM_dupallocN(sce->r.avicodecdata);
+ sce_copy->r.avicodecdata->lpFormat = MEM_dupallocN(sce_copy->r.avicodecdata->lpFormat);
+ sce_copy->r.avicodecdata->lpParms = MEM_dupallocN(sce_copy->r.avicodecdata->lpParms);
}
- if (sce->ed) {
- scen->ed = MEM_callocN(sizeof(Editing), "addseq");
- scen->ed->seqbasep = &scen->ed->seqbase;
- BKE_sequence_base_dupli_recursive(sce, scen, &scen->ed->seqbase, &sce->ed->seqbase, SEQ_DUPE_ALL);
+ if (sce->r.ffcodecdata.properties) { /* intentionally check scen not sce. */
+ sce_copy->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties);
}
+
+ /* before scene copy */
+ BKE_sound_create_scene(sce_copy);
+
+ /* grease pencil */
+ sce_copy->gpd = NULL;
+
+ sce_copy->preview = NULL;
+
+ return sce_copy;
}
-
- /* grease pencil */
- if (scen->gpd) {
+ else {
+ BKE_id_copy_ex(bmain, (ID *)sce, (ID **)&sce_copy, LIB_ID_COPY_ACTIONS, false);
+ id_us_min(&sce_copy->id);
+ id_us_ensure_real(&sce_copy->id);
+
+ /* Extra actions, most notably SCE_FULL_COPY also duplicates several 'children' datablocks... */
+
if (type == SCE_COPY_FULL) {
- scen->gpd = BKE_gpencil_data_duplicate(bmain, scen->gpd, false);
- }
- else if (type == SCE_COPY_EMPTY) {
- scen->gpd = NULL;
+ /* Copy Freestyle LineStyle datablocks. */
+ for (SceneRenderLayer *srl_dst = sce_copy->r.layers.first; srl_dst; srl_dst = srl_dst->next) {
+ for (FreestyleLineSet *lineset = srl_dst->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ if (lineset->linestyle) {
+ /* XXX Not copying anim/actions here? */
+ BKE_id_copy_ex(bmain, (ID *)lineset->linestyle, (ID **)&lineset->linestyle, 0, false);
+ }
+ }
+ }
+
+ /* Full copy of world (included animations) */
+ if (sce_copy->world) {
+ BKE_id_copy_ex(bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS, false);
+ }
+
+ /* Full copy of GreasePencil. */
+ /* XXX Not copying anim/actions here? */
+ if (sce_copy->gpd) {
+ BKE_id_copy_ex(bmain, (ID *)sce_copy->gpd, (ID **)&sce_copy->gpd, 0, false);
+ }
}
else {
- id_us_plus((ID *)scen->gpd);
+ /* Remove sequencer if not full copy */
+ /* XXX Why in Hell? :/ */
+ remove_sequencer_fcurves(sce_copy);
+ BKE_sequencer_editing_free(sce_copy);
}
- }
- BKE_previewimg_id_copy(&scen->id, &sce->id);
+ /* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations
+ * are done outside of blenkernel with ED_objects_single_users! */
+
+ /* camera */
+ if (ELEM(type, SCE_COPY_LINK_DATA, SCE_COPY_FULL)) {
+ ID_NEW_REMAP(sce_copy->camera);
+ }
- return scen;
+ return sce_copy;
+ }
}
void BKE_scene_groups_relink(Scene *sce)
@@ -403,21 +479,20 @@ void BKE_scene_free(Scene *sce)
MEM_freeN(sce->r.avicodecdata);
sce->r.avicodecdata = NULL;
}
- if (sce->r.qtcodecdata) {
- free_qtcodecdata(sce->r.qtcodecdata);
- MEM_freeN(sce->r.qtcodecdata);
- sce->r.qtcodecdata = NULL;
- }
if (sce->r.ffcodecdata.properties) {
IDP_FreeProperty(sce->r.ffcodecdata.properties);
MEM_freeN(sce->r.ffcodecdata.properties);
sce->r.ffcodecdata.properties = NULL;
}
-
+
for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ if (srl->prop != NULL) {
+ IDP_FreeProperty(srl->prop);
+ MEM_freeN(srl->prop);
+ }
BKE_freestyle_config_free(&srl->freestyleConfig);
}
-
+
BLI_freelistN(&sce->markers);
BLI_freelistN(&sce->transform_spaces);
BLI_freelistN(&sce->r.layers);
@@ -440,12 +515,17 @@ void BKE_scene_free(Scene *sce)
BKE_paint_free(&sce->toolsettings->uvsculpt->paint);
MEM_freeN(sce->toolsettings->uvsculpt);
}
+ BKE_paint_free(&sce->toolsettings->imapaint.paint);
+
/* free Grease Pencil Drawing Brushes */
BKE_gpencil_free_brushes(&sce->toolsettings->gp_brushes);
BLI_freelistN(&sce->toolsettings->gp_brushes);
-
- BKE_paint_free(&sce->toolsettings->imapaint.paint);
-
+
+ /* free Grease Pencil interpolation curve */
+ if (sce->toolsettings->gp_interpolate.custom_ipo) {
+ curvemapping_free(sce->toolsettings->gp_interpolate.custom_ipo);
+ }
+
MEM_freeN(sce->toolsettings);
sce->toolsettings = NULL;
}
@@ -558,7 +638,7 @@ void BKE_scene_init(Scene *sce)
sce->r.seq_prev_type = OB_SOLID;
sce->r.seq_rend_type = OB_SOLID;
- sce->r.seq_flag = R_SEQ_GL_PREV;
+ sce->r.seq_flag = 0;
sce->r.threads = 1;
@@ -818,7 +898,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
{
Scene *sce;
- sce = BKE_libblock_alloc(bmain, ID_SCE, name);
+ sce = BKE_libblock_alloc(bmain, ID_SCE, name, 0);
id_us_min(&sce->id);
id_us_ensure_real(&sce->id);
@@ -1502,8 +1582,6 @@ static void scene_update_object_func(TaskPool * __restrict pool, void *taskdata,
if (add_to_stats) {
StatisicsEntry *entry;
- BLI_assert(threadid < BLI_pool_get_num_threads(pool));
-
entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics");
entry->object = object;
entry->start_time = start_time;
@@ -1623,10 +1701,11 @@ static bool scene_need_update_objects(Main *bmain)
static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
{
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskScheduler *task_scheduler;
TaskPool *task_pool;
ThreadedObjectUpdateState state;
bool need_singlethread_pass;
+ bool need_free_scheduler;
/* Early check for whether we need to invoke all the task-based
* things (spawn new ppol, traverse dependency graph and so on).
@@ -1643,6 +1722,15 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
state.scene = scene;
state.scene_parent = scene_parent;
+ if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
+ task_scheduler = BLI_task_scheduler_create(1);
+ need_free_scheduler = true;
+ }
+ else {
+ task_scheduler = BLI_task_scheduler_get();
+ need_free_scheduler = false;
+ }
+
/* Those are only needed when blender is run with --debug argument. */
if (G.debug & G_DEBUG_DEPSGRAPH) {
const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
@@ -1657,9 +1745,6 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
#endif
task_pool = BLI_task_pool_create(task_scheduler, &state);
- if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- BLI_pool_set_num_threads(task_pool, 1);
- }
DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool);
BLI_task_pool_work_and_wait(task_pool);
@@ -1692,6 +1777,10 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
if (need_singlethread_pass) {
scene_update_all_bases(eval_ctx, scene, scene_parent);
}
+
+ if (need_free_scheduler) {
+ BLI_task_scheduler_free(task_scheduler);
+ }
}
static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
@@ -1813,8 +1902,6 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
#endif
{
DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
- /* TODO(sergey): This is to beocme a node in new depsgraph. */
- BKE_mask_update_scene(bmain, scene);
}
/* update sound system animation (TODO, move to depsgraph) */
@@ -1931,11 +2018,10 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
/* Following 2 functions are recursive
* so don't call within 'scene_update_tagged_recursive' */
DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still
+ BKE_mask_evaluate_all_masks(bmain, ctime, true);
}
#endif
- BKE_mask_evaluate_all_masks(bmain, ctime, true);
-
/* Update animated cache files for modifiers. */
BKE_cachefile_update_frame(bmain, sce, ctime, (((double)sce->r.frs_sec) / (double)sce->r.frs_sec_base));
@@ -2044,6 +2130,13 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *
return false;
}
+ BKE_freestyle_config_free(&srl->freestyleConfig);
+
+ if (srl->prop) {
+ IDP_FreeProperty(srl->prop);
+ MEM_freeN(srl->prop);
+ }
+
BLI_remlink(&scene->r.layers, srl);
MEM_freeN(srl);
@@ -2106,7 +2199,7 @@ bool BKE_scene_remove_render_view(Scene *scene, SceneRenderView *srv)
int get_render_subsurf_level(const RenderData *r, int lvl, bool for_render)
{
- if (r->mode & R_SIMPLIFY) {
+ if (r->mode & R_SIMPLIFY) {
if (for_render)
return min_ii(r->simplify_subsurf_render, lvl);
else
@@ -2277,6 +2370,14 @@ int BKE_scene_num_threads(const Scene *scene)
return BKE_render_num_threads(&scene->r);
}
+int BKE_render_preview_pixel_size(const RenderData *r)
+{
+ if (r->preview_pixel_size == 0) {
+ return (U.pixelsize > 1.5f) ? 2 : 1;
+ }
+ return r->preview_pixel_size;
+}
+
/* Apply the needed correction factor to value, based on unit_type (only length-related are affected currently)
* and unit->scale_length.
*/
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 857bd5447c8..df47b89fadc 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -181,6 +181,7 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
BLI_listbase_clear(&newar->ui_lists);
newar->swinid = 0;
newar->regiontimer = NULL;
+ newar->headerstr = NULL;
/* use optional regiondata callback */
if (ar->regiondata) {
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index ce7c520438a..a2c45057bf7 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -684,7 +684,7 @@ static float invGammaCorrect(float c)
else if (i >= RE_GAMMA_TABLE_SIZE) res = powf(c, valid_inv_gamma);
else res = inv_gamma_range_table[i] +
((c - color_domain_table[i]) * inv_gamfactor_table[i]);
-
+
return res;
}
@@ -1074,29 +1074,31 @@ static void do_sub_effect(const SeqRenderData *context, Sequence *UNUSED(seq), f
static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi)
{
- int height, width, temp, fac, fac1, fac2;
+ int temp, fac, fac1, fac2;
unsigned char *rt1, *rt2, *out;
int field = 1;
- width = x;
- height = y;
+ const int width = x;
+ const int height = y;
+ const int xoff = min_ii(XOFF, width);
+ const int yoff = min_ii(YOFF, height);
fac1 = (int) (70.0f * facf0);
fac2 = (int) (70.0f * facf1);
- rt2 = (unsigned char *) (rect2i + YOFF * width);
- rt1 = (unsigned char *) rect1i;
- out = (unsigned char *) outi;
- for (y = 0; y < height - YOFF; y++) {
+ rt2 = rect2i + yoff * 4 * width;
+ rt1 = rect1i;
+ out = outi;
+ for (y = 0; y < height - yoff; y++) {
if (field) fac = fac1;
else fac = fac2;
field = !field;
- memcpy(out, rt1, sizeof(int) * XOFF);
- rt1 += XOFF * 4;
- out += XOFF * 4;
+ memcpy(out, rt1, sizeof(*out) * xoff * 4);
+ rt1 += xoff * 4;
+ out += xoff * 4;
- for (x = XOFF; x < width; x++) {
+ for (x = xoff; x < width; x++) {
temp = ((fac * rt2[3]) >> 8);
*(out++) = MAX2(0, *rt1 - temp); rt1++;
@@ -1105,37 +1107,38 @@ static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned
*(out++) = MAX2(0, *rt1 - temp); rt1++;
rt2 += 4;
}
- rt2 += XOFF * 4;
+ rt2 += xoff * 4;
}
- memcpy(out, rt1, sizeof(int) * YOFF * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
}
static void do_drop_effect_float(float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi)
{
- int height, width;
float temp, fac, fac1, fac2;
float *rt1, *rt2, *out;
int field = 1;
- width = x;
- height = y;
+ const int width = x;
+ const int height = y;
+ const int xoff = min_ii(XOFF, width);
+ const int yoff = min_ii(YOFF, height);
fac1 = 70.0f * facf0;
fac2 = 70.0f * facf1;
- rt2 = (rect2i + YOFF * width);
+ rt2 = rect2i + yoff * 4 * width;
rt1 = rect1i;
out = outi;
- for (y = 0; y < height - YOFF; y++) {
+ for (y = 0; y < height - yoff; y++) {
if (field) fac = fac1;
else fac = fac2;
field = !field;
- memcpy(out, rt1, 4 * sizeof(float) * XOFF);
- rt1 += XOFF * 4;
- out += XOFF * 4;
+ memcpy(out, rt1, sizeof(*out) * xoff * 4);
+ rt1 += xoff * 4;
+ out += xoff * 4;
- for (x = XOFF; x < width; x++) {
+ for (x = xoff; x < width; x++) {
temp = fac * rt2[3];
*(out++) = MAX2(0.0f, *rt1 - temp); rt1++;
@@ -1144,9 +1147,9 @@ static void do_drop_effect_float(float facf0, float facf1, int x, int y, float *
*(out++) = MAX2(0.0f, *rt1 - temp); rt1++;
rt2 += 4;
}
- rt2 += XOFF * 4;
+ rt2 += xoff * 4;
}
- memcpy(out, rt1, 4 * sizeof(float) * YOFF * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
}
/*********************** Mul *************************/
@@ -1858,7 +1861,7 @@ static void RVBlurBitmap2_float(float *map, int width, int height, float blur, i
float *filter = NULL;
int x, y, i, fx, fy;
int index, ix, halfWidth;
- float fval, k, curColor[3], curColor2[3], weight = 0;
+ float fval, k, curColor[4], curColor2[4], weight = 0;
/* If we're not really blurring, bail out */
if (blur <= 0)
@@ -1903,47 +1906,38 @@ static void RVBlurBitmap2_float(float *map, int width, int height, float blur, i
for (y = 0; y < height; y++) {
/* Do the left & right strips */
for (x = 0; x < halfWidth; x++) {
- index = (x + y * width) * 4;
fx = 0;
- curColor[0] = curColor[1] = curColor[2] = 0.0f;
- curColor2[0] = curColor2[1] = curColor2[2] = 0.0f;
+ zero_v4(curColor);
+ zero_v4(curColor2);
for (i = x - halfWidth; i < x + halfWidth; i++) {
if ((i >= 0) && (i < width)) {
- curColor[0] += map[(i + y * width) * 4 + GlowR] * filter[fx];
- curColor[1] += map[(i + y * width) * 4 + GlowG] * filter[fx];
- curColor[2] += map[(i + y * width) * 4 + GlowB] * filter[fx];
+ index = (i + y * width) * 4;
+ madd_v4_v4fl(curColor, map + index, filter[fx]);
- curColor2[0] += map[(width - 1 - i + y * width) * 4 + GlowR] * filter[fx];
- curColor2[1] += map[(width - 1 - i + y * width) * 4 + GlowG] * filter[fx];
- curColor2[2] += map[(width - 1 - i + y * width) * 4 + GlowB] * filter[fx];
+ index = (width - 1 - i + y * width) * 4;
+ madd_v4_v4fl(curColor2, map + index, filter[fx]);
}
fx++;
}
- temp[index + GlowR] = curColor[0];
- temp[index + GlowG] = curColor[1];
- temp[index + GlowB] = curColor[2];
-
- temp[((width - 1 - x + y * width) * 4) + GlowR] = curColor2[0];
- temp[((width - 1 - x + y * width) * 4) + GlowG] = curColor2[1];
- temp[((width - 1 - x + y * width) * 4) + GlowB] = curColor2[2];
+ index = (x + y * width) * 4;
+ copy_v4_v4(temp + index, curColor);
+ index = (width - 1 - x + y * width) * 4;
+ copy_v4_v4(temp + index, curColor2);
}
/* Do the main body */
for (x = halfWidth; x < width - halfWidth; x++) {
- index = (x + y * width) * 4;
fx = 0;
- zero_v3(curColor);
+ zero_v4(curColor);
for (i = x - halfWidth; i < x + halfWidth; i++) {
- curColor[0] += map[(i + y * width) * 4 + GlowR] * filter[fx];
- curColor[1] += map[(i + y * width) * 4 + GlowG] * filter[fx];
- curColor[2] += map[(i + y * width) * 4 + GlowB] * filter[fx];
+ index = (i + y * width) * 4;
+ madd_v4_v4fl(curColor, map + index, filter[fx]);
fx++;
}
- temp[index + GlowR] = curColor[0];
- temp[index + GlowG] = curColor[1];
- temp[index + GlowB] = curColor[2];
+ index = (x + y * width) * 4;
+ copy_v4_v4(temp + index, curColor);
}
}
@@ -1954,46 +1948,39 @@ static void RVBlurBitmap2_float(float *map, int width, int height, float blur, i
for (x = 0; x < width; x++) {
/* Do the top & bottom strips */
for (y = 0; y < halfWidth; y++) {
- index = (x + y * width) * 4;
fy = 0;
- zero_v3(curColor);
- zero_v3(curColor2);
+ zero_v4(curColor);
+ zero_v4(curColor2);
for (i = y - halfWidth; i < y + halfWidth; i++) {
if ((i >= 0) && (i < height)) {
/* Bottom */
- curColor[0] += map[(x + i * width) * 4 + GlowR] * filter[fy];
- curColor[1] += map[(x + i * width) * 4 + GlowG] * filter[fy];
- curColor[2] += map[(x + i * width) * 4 + GlowB] * filter[fy];
+ index = (x + i * width) * 4;
+ madd_v4_v4fl(curColor, map + index, filter[fy]);
/* Top */
- curColor2[0] += map[(x + (height - 1 - i) * width) * 4 + GlowR] * filter[fy];
- curColor2[1] += map[(x + (height - 1 - i) * width) * 4 + GlowG] * filter[fy];
- curColor2[2] += map[(x + (height - 1 - i) * width) * 4 + GlowB] * filter[fy];
+ index = (x + (height - 1 - i) * width) * 4;
+ madd_v4_v4fl(curColor2, map + index, filter[fy]);
}
fy++;
}
- temp[index + GlowR] = curColor[0];
- temp[index + GlowG] = curColor[1];
- temp[index + GlowB] = curColor[2];
- temp[((x + (height - 1 - y) * width) * 4) + GlowR] = curColor2[0];
- temp[((x + (height - 1 - y) * width) * 4) + GlowG] = curColor2[1];
- temp[((x + (height - 1 - y) * width) * 4) + GlowB] = curColor2[2];
+ index = (x + y * width) * 4;
+ copy_v4_v4(temp + index, curColor);
+
+ index = (x + (height - 1 - y) * width) * 4;
+ copy_v4_v4(temp + index, curColor2);
}
/* Do the main body */
for (y = halfWidth; y < height - halfWidth; y++) {
- index = (x + y * width) * 4;
fy = 0;
- zero_v3(curColor);
+ zero_v4(curColor);
for (i = y - halfWidth; i < y + halfWidth; i++) {
- curColor[0] += map[(x + i * width) * 4 + GlowR] * filter[fy];
- curColor[1] += map[(x + i * width) * 4 + GlowG] * filter[fy];
- curColor[2] += map[(x + i * width) * 4 + GlowB] * filter[fy];
+ index = (x + i * width) * 4;
+ madd_v4_v4fl(curColor, map + index, filter[fy]);
fy++;
}
- temp[index + GlowR] = curColor[0];
- temp[index + GlowG] = curColor[1];
- temp[index + GlowB] = curColor[2];
+ index = (x + y * width) * 4;
+ copy_v4_v4(temp + index, curColor);
}
}
@@ -2012,10 +1999,10 @@ static void RVAddBitmaps_float(float *a, float *b, float *c, int width, int heig
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
index = (x + y * width) * 4;
- c[index + GlowR] = MIN2(1.0f, a[index + GlowR] + b[index + GlowR]);
- c[index + GlowG] = MIN2(1.0f, a[index + GlowG] + b[index + GlowG]);
- c[index + GlowB] = MIN2(1.0f, a[index + GlowB] + b[index + GlowB]);
- c[index + GlowA] = MIN2(1.0f, a[index + GlowA] + b[index + GlowA]);
+ c[index + GlowR] = min_ff(1.0f, a[index + GlowR] + b[index + GlowR]);
+ c[index + GlowG] = min_ff(1.0f, a[index + GlowG] + b[index + GlowG]);
+ c[index + GlowB] = min_ff(1.0f, a[index + GlowB] + b[index + GlowB]);
+ c[index + GlowA] = min_ff(1.0f, a[index + GlowA] + b[index + GlowA]);
}
}
}
@@ -2032,10 +2019,10 @@ static void RVIsolateHighlights_float(float *in, float *out, int width, int heig
/* Isolate the intensity */
intensity = (in[index + GlowR] + in[index + GlowG] + in[index + GlowB] - threshold);
if (intensity > 0) {
- out[index + GlowR] = MIN2(clamp, (in[index + GlowR] * boost * intensity));
- out[index + GlowG] = MIN2(clamp, (in[index + GlowG] * boost * intensity));
- out[index + GlowB] = MIN2(clamp, (in[index + GlowB] * boost * intensity));
- out[index + GlowA] = MIN2(clamp, (in[index + GlowA] * boost * intensity));
+ out[index + GlowR] = min_ff(clamp, (in[index + GlowR] * boost * intensity));
+ out[index + GlowG] = min_ff(clamp, (in[index + GlowG] * boost * intensity));
+ out[index + GlowB] = min_ff(clamp, (in[index + GlowB] * boost * intensity));
+ out[index + GlowA] = min_ff(clamp, (in[index + GlowA] * boost * intensity));
}
else {
out[index + GlowR] = 0;
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index 95c6b7736e1..e2f74dbab3c 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -34,8 +34,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@@ -202,21 +202,22 @@ static void whiteBalance_apply_threaded(int width, int height, unsigned char *re
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
int pixel_index = (y * width + x) * 4;
- float result[4], mask[3] = {1.0f, 1.0f, 1.0f};
+ float rgba[4], result[4], mask[3] = {1.0f, 1.0f, 1.0f};
if (rect_float) {
- copy_v3_v3(result, rect_float + pixel_index);
+ copy_v3_v3(rgba, rect_float + pixel_index);
}
else {
- straight_uchar_to_premul_float(result, rect + pixel_index);
+ straight_uchar_to_premul_float(rgba, rect + pixel_index);
}
+ copy_v4_v4(result, rgba);
#if 0
mul_v3_v3(result, multiplier);
#else
/* similar to division without the clipping */
for (int i = 0; i < 3; i++) {
- result[i] = 1.0f - powf(1.0f - result[i], multiplier[i]);
+ result[i] = 1.0f - powf(1.0f - rgba[i], multiplier[i]);
}
#endif
@@ -227,9 +228,9 @@ static void whiteBalance_apply_threaded(int width, int height, unsigned char *re
rgb_uchar_to_float(mask, mask_rect + pixel_index);
}
- result[0] = result[0] * (1.0f - mask[0]) + result[0] * mask[0];
- result[1] = result[1] * (1.0f - mask[1]) + result[1] * mask[1];
- result[2] = result[2] * (1.0f - mask[2]) + result[2] * mask[2];
+ result[0] = rgba[0] * (1.0f - mask[0]) + result[0] * mask[0];
+ result[1] = rgba[1] * (1.0f - mask[1]) + result[1] * mask[1];
+ result[2] = rgba[2] * (1.0f - mask[2]) + result[2] * mask[2];
if (rect_float) {
copy_v3_v3(rect_float + pixel_index, result);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 65d751a8a72..9b0db300e6d 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -320,7 +320,8 @@ void BKE_sequencer_free_clipboard(void)
/* Manage pointers in the clipboard.
* note that these pointers should _never_ be access in the sequencer,
* they are only for storage while in the clipboard
- * notice 'newid' is used for temp pointer storage here, validate on access.
+ * notice 'newid' is used for temp pointer storage here, validate on access (this is safe usage,
+ * since those datablocks are fully out of Main lists).
*/
#define ID_PT (*id_pt)
static void seqclipboard_ptr_free(ID **id_pt)
@@ -376,6 +377,8 @@ static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt)
}
break;
}
+ default:
+ break;
}
}
@@ -479,55 +482,77 @@ void BKE_sequencer_editing_free(Scene *scene)
static void sequencer_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf)
{
- if (ibuf->rect_float) {
+#if 0
+ /* Bute buffer is supposed to be in sequencer working space already. */
+ if (ibuf->rect != NULL) {
+ IMB_colormanagement_assign_rect_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
+ }
+#endif
+ if (ibuf->rect_float != NULL) {
IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
}
}
void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make_float)
{
- const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+ /* Early output check: if both buffers are NULL we have nothing to convert. */
+ if (ibuf->rect_float == NULL && ibuf->rect == NULL) {
+ return;
+ }
+ /* Get common conversion settings. */
const char *to_colorspace = scene->sequencer_colorspace_settings.name;
- const char *float_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
-
- if (!ibuf->rect_float) {
- if (ibuf->rect) {
- const char *byte_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
- if (make_float || !STREQ(to_colorspace, byte_colorspace)) {
- /* If byte space is not in sequencer's working space, we deliver float color space,
- * this is to to prevent data loss.
- */
-
- /* when converting byte buffer to float in sequencer we need to make float
- * buffer be in sequencer's working space, which is currently only doable
- * from linear space.
- */
-
- /*
- * OCIO_TODO: would be nice to support direct single transform from byte to sequencer's
- */
-
- IMB_float_from_rect(ibuf);
- }
- else {
- return;
- }
+ /* Perform actual conversion logic. */
+ if (ibuf->rect_float == NULL) {
+ /* We are not requested to give float buffer and byte buffer is already
+ * in thee required colorspace. Can skip doing anything here.
+ */
+ const char *from_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
+ if (!make_float && STREQ(from_colorspace, to_colorspace)) {
+ return;
+ }
+ if (false) {
+ /* The idea here is to provide as fast playback as possible and
+ * enforcing float buffer here (a) uses more cache memory (b) might
+ * make some other effects slower to apply.
+ *
+ * However, this might also have negative effect by adding weird
+ * artifacts which will then not happen in final render.
+ */
+ IMB_colormanagement_transform_byte_threaded(
+ (unsigned char *)ibuf->rect, ibuf->x, ibuf->y, ibuf->channels,
+ from_colorspace, to_colorspace);
}
else {
- return;
+ /* We perform conversion to a float buffer so we don't worry about
+ * precision loss.
+ */
+ imb_addrectfloatImBuf(ibuf);
+ IMB_colormanagement_transform_from_byte_threaded(
+ ibuf->rect_float, (unsigned char *)ibuf->rect,
+ ibuf->x, ibuf->y, ibuf->channels,
+ from_colorspace, to_colorspace);
+ /* We don't need byte buffer anymore. */
+ imb_freerectImBuf(ibuf);
}
}
-
- if (from_colorspace && from_colorspace[0] != '\0') {
- if (ibuf->rect)
+ else {
+ const char *from_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
+ /* Unknown input color space, can't perform conversion. */
+ if (from_colorspace == NULL || from_colorspace[0] == '\0') {
+ return;
+ }
+ /* We don't want both byte and float buffers around: they'll either run
+ * out of sync or conversion of byte buffer will loose precision in there.
+ */
+ if (ibuf->rect != NULL) {
imb_freerectImBuf(ibuf);
-
- if (!STREQ(float_colorspace, to_colorspace)) {
- IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
- from_colorspace, to_colorspace, true);
- sequencer_imbuf_assign_spaces(scene, ibuf);
}
+ IMB_colormanagement_transform_threaded(ibuf->rect_float,
+ ibuf->x, ibuf->y, ibuf->channels,
+ from_colorspace, to_colorspace,
+ true);
}
+ sequencer_imbuf_assign_spaces(scene, ibuf);
}
void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf)
@@ -1755,7 +1780,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
if (proxy->anim == NULL) {
return NULL;
}
-
+
seq_open_anim_file(context->scene, seq, true);
sanim = seq->anims.first;
@@ -1763,7 +1788,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
}
-
+
if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
return NULL;
}
@@ -2062,7 +2087,7 @@ void BKE_sequencer_proxy_set(struct Sequence *seq, bool value)
}
}
else {
- seq->flag ^= SEQ_USE_PROXY;
+ seq->flag &= ~SEQ_USE_PROXY;
}
}
@@ -3213,7 +3238,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
const bool is_background = G.background;
const bool do_seq_gl = is_rendering ?
0 /* (context->scene->r.seq_flag & R_SEQ_GL_REND) */ :
- (context->scene->r.seq_flag & R_SEQ_GL_PREV) != 0;
+ (context->scene->r.seq_prev_type) != OB_RENDER;
// bool have_seq = false; /* UNUSED */
bool have_comp = false;
bool use_gpencil = true;
@@ -3295,7 +3320,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
}
}
else {
- Render *re = RE_GetRender(scene->id.name);
+ Render *re = RE_GetSceneRender(scene);
const int totviews = BKE_scene_multiview_num_views_get(&scene->r);
int i;
ImBuf **ibufs_arr;
@@ -3312,7 +3337,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
*/
if (!is_thread_main || is_rendering == false || is_background || context->eval_ctx->mode == DAG_EVAL_RENDER) {
if (re == NULL)
- re = RE_NewRender(scene->id.name);
+ re = RE_NewSceneRender(scene);
BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false);
@@ -4170,9 +4195,10 @@ static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *cha
if (free_imbuf) {
if (ibuf_change) {
- if (seq->type == SEQ_TYPE_MOVIE)
+ if (seq->type == SEQ_TYPE_MOVIE) {
BKE_sequence_free_anim(seq);
- if (seq->type == SEQ_TYPE_SPEED) {
+ }
+ else if (seq->type == SEQ_TYPE_SPEED) {
BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
}
}
@@ -5162,6 +5188,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */
if (sound->playback_handle == NULL) {
+ BKE_libblock_free(bmain, sound);
#if 0
if (op)
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
@@ -5349,9 +5376,8 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
return seq;
}
-static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dupe_flag)
+static Sequence *seq_dupli(const Scene *scene_src, Scene *scene_dst, Sequence *seq, int dupe_flag, const int flag)
{
- Scene *sce_audio = scene_to ? scene_to : scene;
Sequence *seqn = MEM_dupallocN(seq);
seq->tmp = seqn;
@@ -5375,7 +5401,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
}
if (seq->prop) {
- seqn->prop = IDP_CopyProperty(seq->prop);
+ seqn->prop = IDP_CopyProperty_ex(seq->prop, flag);
}
if (seqn->modifiers.first) {
@@ -5394,7 +5420,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
else if (seq->type == SEQ_TYPE_SCENE) {
seqn->strip->stripdata = NULL;
if (seq->scene_sound)
- seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(sce_audio, seqn);
+ seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene_dst, seqn);
}
else if (seq->type == SEQ_TYPE_MOVIECLIP) {
/* avoid assert */
@@ -5411,9 +5437,11 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
seqn->strip->stripdata =
MEM_dupallocN(seq->strip->stripdata);
if (seq->scene_sound)
- seqn->scene_sound = BKE_sound_add_scene_sound_defaults(sce_audio, seqn);
+ seqn->scene_sound = BKE_sound_add_scene_sound_defaults(scene_dst, seqn);
- id_us_plus((ID *)seqn->sound);
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)seqn->sound);
+ }
}
else if (seq->type == SEQ_TYPE_IMAGE) {
seqn->strip->stripdata =
@@ -5433,11 +5461,15 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
BLI_assert(0);
}
- if (dupe_flag & SEQ_DUPE_UNIQUE_NAME)
- BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqn);
+ if (scene_src == scene_dst) {
+ if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) {
+ BKE_sequence_base_unique_name_recursive(&scene_dst->ed->seqbase, seqn);
+ }
- if (dupe_flag & SEQ_DUPE_ANIM)
- BKE_sequencer_dupe_animdata(scene, seq->name + 2, seqn->name + 2);
+ if (dupe_flag & SEQ_DUPE_ANIM) {
+ BKE_sequencer_dupe_animdata(scene_dst, seq->name + 2, seqn->name + 2);
+ }
+ }
return seqn;
}
@@ -5464,16 +5496,16 @@ static void seq_new_fix_links_recursive(Sequence *seq)
}
}
-Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence *seq, int dupe_flag)
+Sequence *BKE_sequence_dupli_recursive(const Scene *scene_src, Scene *scene_dst, Sequence *seq, int dupe_flag)
{
Sequence *seqn;
seq->tmp = NULL;
- seqn = seq_dupli(scene, scene_to, seq, dupe_flag);
+ seqn = seq_dupli(scene_src, scene_dst, seq, dupe_flag, 0);
if (seq->type == SEQ_TYPE_META) {
Sequence *s;
for (s = seq->seqbase.first; s; s = s->next) {
- Sequence *n = BKE_sequence_dupli_recursive(scene, scene_to, s, dupe_flag);
+ Sequence *n = BKE_sequence_dupli_recursive(scene_src, scene_dst, s, dupe_flag);
if (n) {
BLI_addtail(&seqn->seqbase, n);
}
@@ -5486,19 +5518,19 @@ Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence *
}
void BKE_sequence_base_dupli_recursive(
- Scene *scene, Scene *scene_to, ListBase *nseqbase, ListBase *seqbase,
- int dupe_flag)
+ const Scene *scene_src, Scene *scene_dst, ListBase *nseqbase, const ListBase *seqbase,
+ int dupe_flag, const int flag)
{
Sequence *seq;
Sequence *seqn = NULL;
- Sequence *last_seq = BKE_sequencer_active_get(scene);
+ Sequence *last_seq = BKE_sequencer_active_get((Scene *)scene_src);
/* always include meta's strips */
int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL;
for (seq = seqbase->first; seq; seq = seq->next) {
seq->tmp = NULL;
if ((seq->flag & SELECT) || (dupe_flag & SEQ_DUPE_ALL)) {
- seqn = seq_dupli(scene, scene_to, seq, dupe_flag);
+ seqn = seq_dupli(scene_src, scene_dst, seq, dupe_flag, flag);
if (seqn) { /*should never fail */
if (dupe_flag & SEQ_DUPE_CONTEXT) {
seq->flag &= ~SEQ_ALLSEL;
@@ -5508,13 +5540,13 @@ void BKE_sequence_base_dupli_recursive(
BLI_addtail(nseqbase, seqn);
if (seq->type == SEQ_TYPE_META) {
BKE_sequence_base_dupli_recursive(
- scene, scene_to, &seqn->seqbase, &seq->seqbase,
- dupe_flag_recursive);
+ scene_src, scene_dst, &seqn->seqbase, &seq->seqbase,
+ dupe_flag_recursive, flag);
}
if (dupe_flag & SEQ_DUPE_CONTEXT) {
if (seq == last_seq) {
- BKE_sequencer_active_set(scene, seqn);
+ BKE_sequencer_active_set(scene_dst, seqn);
}
}
}
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 7094d5a3547..f9d1793d7cb 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -152,6 +152,9 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
+ if (calc->target != NULL && calc->target->getNumVerts(calc->target) == 0) {
+ return;
+ }
TIMEIT_BENCH(bvhtree_from_mesh_verts(&treeData, calc->target, 0.0, 2, 6), bvhtree_verts);
if (treeData.tree == NULL) {
@@ -376,6 +379,9 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
return;
+ if (calc->target != NULL && calc->target->getNumPolys(calc->target) == 0) {
+ return;
+ }
/* Prepare data to retrieve the direction in which we should project each vertex */
if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
@@ -432,7 +438,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
if (targ_tree) {
BVHTree *aux_tree = NULL;
void *aux_callback = NULL;
- if (auxMesh != NULL) {
+ if (auxMesh != NULL && auxMesh->getNumPolys(auxMesh) != 0) {
/* use editmesh to avoid array allocation */
if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
emaux = BKE_editmesh_from_object(calc->smd->auxTarget);
@@ -560,6 +566,10 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
+ if (calc->target->getNumPolys(calc->target) == 0) {
+ return;
+ }
+
/* Create a bvh-tree of the given target */
bvhtree_from_mesh_looptri(&treeData, calc->target, 0.0, 2, 6);
if (treeData.tree == NULL) {
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index e8970d416e9..fcf4724bd1c 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -677,7 +677,7 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
tsmd->flow->texture_size = smd->flow->texture_size;
tsmd->flow->texture_offset = smd->flow->texture_offset;
- BLI_strncpy(tsmd->flow->uvlayer_name, tsmd->flow->uvlayer_name, sizeof(tsmd->flow->uvlayer_name));
+ BLI_strncpy(tsmd->flow->uvlayer_name, smd->flow->uvlayer_name, sizeof(tsmd->flow->uvlayer_name));
tsmd->flow->vgroup_density = smd->flow->vgroup_density;
tsmd->flow->type = smd->flow->type;
@@ -758,15 +758,14 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
/* find the nearest point on the mesh */
if (BLI_bvhtree_find_nearest(data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != -1) {
const MLoopTri *lt = &data->looptri[nearest.index];
- float weights[4];
+ float weights[3];
int v1, v2, v3;
/* calculate barycentric weights for nearest point */
v1 = data->mloop[lt->tri[0]].v;
v2 = data->mloop[lt->tri[1]].v;
v3 = data->mloop[lt->tri[2]].v;
- interp_weights_face_v3(
- weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, NULL, nearest.co);
+ interp_weights_tri_v3(weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
// DG TODO
if (data->has_velocity)
@@ -1454,7 +1453,7 @@ static void sample_derivedmesh(
/* find the nearest point on the mesh */
if (BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
- float weights[4];
+ float weights[3];
int v1, v2, v3, f_index = nearest.index;
float n1[3], n2[3], n3[3], hit_normal[3];
@@ -1471,7 +1470,7 @@ static void sample_derivedmesh(
v1 = mloop[mlooptri[f_index].tri[0]].v;
v2 = mloop[mlooptri[f_index].tri[1]].v;
v3 = mloop[mlooptri[f_index].tri[2]].v;
- interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, nearest.co);
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
/* apply normal directional velocity */
@@ -2693,7 +2692,6 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm);
smd->flow->dm = CDDM_copy(dm);
- DM_ensure_looptri(smd->flow->dm);
if (scene->r.cfra > smd->time)
{
@@ -2716,7 +2714,6 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
smd->coll->dm->release(smd->coll->dm);
smd->coll->dm = CDDM_copy(dm);
- DM_ensure_looptri(smd->coll->dm);
}
smd->time = scene->r.cfra;
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 03cf33083da..3052a708137 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -1856,19 +1856,21 @@ static void dfdx_spring(int ia, int ic, int op, float dir[3], float L, float len
float m, delta_ij;
int i, j;
if (L < len) {
- for (i=0;i<3;i++)
+ for (i=0;i<3;i++) {
for (j=0;j<3;j++) {
delta_ij = (i==j ? (1.0f): (0.0f));
m=factor*(dir[i]*dir[j] + (1-L/len)*(delta_ij - dir[i]*dir[j]));
EIG_linear_solver_matrix_add(ia+i, op+ic+j, m);
}
+ }
}
else {
- for (i=0;i<3;i++)
+ for (i=0;i<3;i++) {
for (j=0;j<3;j++) {
m=factor*dir[i]*dir[j];
EIG_linear_solver_matrix_add(ia+i, op+ic+j, m);
}
+ }
}
}
@@ -2233,9 +2235,9 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t
static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, float timenow)
{
-/* rule we never alter free variables :bp->vec bp->pos in here !
- * this will ruin adaptive stepsize AKA heun! (BM)
- */
+ /* rule we never alter free variables :bp->vec bp->pos in here !
+ * this will ruin adaptive stepsize AKA heun! (BM)
+ */
SoftBody *sb= ob->soft; /* is supposed to be there */
/*BodyPoint *bproot;*/ /* UNUSED */
ListBase *do_effector = NULL;
@@ -3410,7 +3412,7 @@ static void softbody_update_positions(Object *ob, SoftBody *sb, float (*vertexCo
* lloc, lrot, lscale are allowed to be NULL, just in case you don't need it.
* should be pretty useful for pythoneers :)
* not! velocity .. 2nd order stuff
- * vcloud_estimate_transform see
+ * vcloud_estimate_transform_v3 see
*/
void SB_estimate_transform(Object *ob, float lloc[3], float lrot[3][3], float lscale[3][3])
@@ -3434,7 +3436,7 @@ void SB_estimate_transform(Object *ob, float lloc[3], float lrot[3][3], float ls
copy_v3_v3(opos[a], bp->pos);
}
- vcloud_estimate_transform(sb->totpoint, opos, NULL, rpos, NULL, com, rcom, lrot, lscale);
+ vcloud_estimate_transform_v3(sb->totpoint, opos, NULL, rpos, NULL, com, rcom, lrot, lscale);
//sub_v3_v3(com, rcom);
if (lloc) copy_v3_v3(lloc, com);
copy_v3_v3(sb->lcom, com);
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index f20885b1e8f..45d1f969d64 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -83,7 +83,7 @@ bSound *BKE_sound_new_file(struct Main *bmain, const char *filepath)
BLI_path_abs(str, path);
- sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath));
+ sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0);
BLI_strncpy(sound->name, filepath, FILE_MAX);
/* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */
@@ -147,12 +147,40 @@ void BKE_sound_free(bSound *sound)
BKE_sound_free_waveform(sound);
+#endif /* WITH_AUDASPACE */
if (sound->spinlock) {
BLI_spin_end(sound->spinlock);
MEM_freeN(sound->spinlock);
sound->spinlock = NULL;
- }
-#endif /* WITH_AUDASPACE */
+ }
+}
+
+/**
+ * Only copy internal data of Sound ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_sound_copy_data(Main *bmain, bSound *sound_dst, const bSound *UNUSED(sound_src), const int UNUSED(flag))
+{
+ sound_dst->handle = NULL;
+ sound_dst->cache = NULL;
+ sound_dst->waveform = NULL;
+ sound_dst->playback_handle = NULL;
+ sound_dst->spinlock = NULL; /* Think this is OK? Otherwise, easy to create new spinlock here... */
+
+ /* Just to be sure, should not have any value actually after reading time. */
+ sound_dst->ipo = NULL;
+ sound_dst->newpackedfile = NULL;
+
+ if (sound_dst->packedfile) {
+ sound_dst->packedfile = dupPackedFile(sound_dst->packedfile);
+ }
+
+ /* Initialize whole runtime (audaspace) stuff. */
+ BKE_sound_load(bmain, sound_dst);
}
void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local)
@@ -167,6 +195,10 @@ static const char *force_device = NULL;
#ifdef WITH_JACK
static void sound_sync_callback(void *data, int mode, float time)
{
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return;
+
struct Main *bmain = (struct Main *)data;
struct Scene *scene;
@@ -450,6 +482,16 @@ void BKE_sound_destroy_scene(struct Scene *scene)
AUD_destroySet(scene->speaker_handles);
}
+void BKE_sound_reset_scene_specs(struct Scene *scene)
+{
+ AUD_Specs specs;
+
+ specs.channels = AUD_Device_getChannels(sound_device);
+ specs.rate = AUD_Device_getRate(sound_device);
+
+ AUD_Sequence_setSpecs(scene->sound_scene, specs);
+}
+
void BKE_sound_mute_scene(struct Scene *scene, int muted)
{
if (scene->sound_scene)
@@ -576,15 +618,10 @@ void BKE_sound_update_sequencer(struct Main *main, bSound *sound)
static void sound_start_play_scene(struct Scene *scene)
{
- AUD_Specs specs;
-
if (scene->playback_handle)
AUD_Handle_stop(scene->playback_handle);
- specs.channels = AUD_Device_getChannels(sound_device);
- specs.rate = AUD_Device_getRate(sound_device);
-
- AUD_Sequence_setSpecs(scene->sound_scene, specs);
+ BKE_sound_reset_scene_specs(scene);
if ((scene->playback_handle = AUD_Device_play(sound_device, scene->sound_scene, 1)))
AUD_Handle_setLoopCount(scene->playback_handle, -1);
@@ -693,6 +730,10 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene)
float BKE_sound_sync_scene(struct Scene *scene)
{
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return NAN_FLT;
+
if (scene->playback_handle) {
if (scene->audio.flag & AUDIO_SYNC)
return AUD_getSynchronizerPosition(scene->playback_handle);
@@ -704,6 +745,10 @@ float BKE_sound_sync_scene(struct Scene *scene)
int BKE_sound_scene_playing(struct Scene *scene)
{
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return -1;
+
if (scene->audio.flag & AUDIO_SYNC)
return AUD_isSynchronizerPlaying();
else
@@ -898,6 +943,7 @@ void BKE_sound_delete_cache(struct bSound *UNUSED(sound)) {}
void BKE_sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {}
void BKE_sound_create_scene(struct Scene *UNUSED(scene)) {}
void BKE_sound_destroy_scene(struct Scene *UNUSED(scene)) {}
+void BKE_sound_reset_scene_specs(struct Scene *UNUSED(scene)) {}
void BKE_sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {}
void *BKE_sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence),
int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index ee6886e3fb2..9d604a9382a 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -61,25 +61,31 @@ void *BKE_speaker_add(Main *bmain, const char *name)
{
Speaker *spk;
- spk = BKE_libblock_alloc(bmain, ID_SPK, name);
+ spk = BKE_libblock_alloc(bmain, ID_SPK, name, 0);
BKE_speaker_init(spk);
return spk;
}
-Speaker *BKE_speaker_copy(Main *bmain, Speaker *spk)
+/**
+ * Only copy internal data of Speaker ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_speaker_copy_data(Main *UNUSED(bmain), Speaker *UNUSED(spk_dst), const Speaker *UNUSED(spk_src), const int UNUSED(flag))
{
- Speaker *spkn;
-
- spkn = BKE_libblock_copy(bmain, &spk->id);
-
- if (spkn->sound)
- id_us_plus(&spkn->sound->id);
-
- BKE_id_copy_ensure_local(bmain, &spk->id, &spkn->id);
+ /* Nothing to do! */
+}
- return spkn;
+Speaker *BKE_speaker_copy(Main *bmain, const Speaker *spk)
+{
+ Speaker *spk_copy;
+ BKE_id_copy_ex(bmain, &spk->id, (ID **)&spk_copy, 0, false);
+ return spk_copy;
}
void BKE_speaker_make_local(Main *bmain, Speaker *spk, const bool lib_local)
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 6d57c5f09e8..0cdc97c829f 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -42,6 +42,8 @@
#include <math.h>
#include <float.h>
+#include "atomic_ops.h"
+
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
@@ -2196,12 +2198,12 @@ static void ccgDM_buffer_copy_color(
for (S = 0; S < numVerts; S++) {
for (y = 0; y < gridFaces; y++) {
for (x = 0; x < gridFaces; x++) {
- copy_v3_v3_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]);
- copy_v3_v3_uchar(&varray[start + 3], &mloopcol[iface * 16 + 12]);
- copy_v3_v3_uchar(&varray[start + 6], &mloopcol[iface * 16 + 8]);
- copy_v3_v3_uchar(&varray[start + 9], &mloopcol[iface * 16 + 4]);
+ copy_v4_v4_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]);
+ copy_v4_v4_uchar(&varray[start + 4], &mloopcol[iface * 16 + 12]);
+ copy_v4_v4_uchar(&varray[start + 8], &mloopcol[iface * 16 + 8]);
+ copy_v4_v4_uchar(&varray[start + 12], &mloopcol[iface * 16 + 4]);
- start += 12;
+ start += 16;
iface++;
}
}
@@ -3681,6 +3683,11 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
int gridFaces = gridSize - 1, totface;
int prev_mat_nr = -1;
+ if (ccgdm->pbvh) {
+ if (G.debug_value == 14)
+ BKE_pbvh_draw_BB(ccgdm->pbvh);
+ }
+
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
int new_matnr;
@@ -3791,16 +3798,16 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
- if (cp) glColor3ubv(&cp[4]);
+ if (cp) glColor4ubv(&cp[4]);
glNormal3fv(ln[1]);
glVertex3fv(d);
- if (cp) glColor3ubv(&cp[8]);
+ if (cp) glColor4ubv(&cp[8]);
glNormal3fv(ln[2]);
glVertex3fv(c);
- if (cp) glColor3ubv(&cp[12]);
+ if (cp) glColor4ubv(&cp[12]);
glNormal3fv(ln[3]);
glVertex3fv(b);
- if (cp) glColor3ubv(&cp[0]);
+ if (cp) glColor4ubv(&cp[0]);
glNormal3fv(ln[0]);
glVertex3fv(a);
@@ -3818,10 +3825,10 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
a = CCG_grid_elem(&key, faceGridData, x, y + 0);
b = CCG_grid_elem(&key, faceGridData, x, y + 1);
- if (cp) glColor3ubv(&cp[0]);
+ if (cp) glColor4ubv(&cp[0]);
glNormal3fv(CCG_elem_no(&key, a));
glVertex3fv(CCG_elem_co(&key, a));
- if (cp) glColor3ubv(&cp[4]);
+ if (cp) glColor4ubv(&cp[4]);
glNormal3fv(CCG_elem_no(&key, b));
glVertex3fv(CCG_elem_co(&key, b));
@@ -3833,10 +3840,10 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
a = CCG_grid_elem(&key, faceGridData, x, y + 0);
b = CCG_grid_elem(&key, faceGridData, x, y + 1);
- if (cp) glColor3ubv(&cp[12]);
+ if (cp) glColor4ubv(&cp[12]);
glNormal3fv(CCG_elem_no(&key, a));
glVertex3fv(CCG_elem_co(&key, a));
- if (cp) glColor3ubv(&cp[8]);
+ if (cp) glColor4ubv(&cp[8]);
glNormal3fv(CCG_elem_no(&key, b));
glVertex3fv(CCG_elem_co(&key, b));
@@ -3856,13 +3863,13 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
ccgDM_glNormalFast(a, b, c, d);
- if (cp) glColor3ubv(&cp[4]);
+ if (cp) glColor4ubv(&cp[4]);
glVertex3fv(d);
- if (cp) glColor3ubv(&cp[8]);
+ if (cp) glColor4ubv(&cp[8]);
glVertex3fv(c);
- if (cp) glColor3ubv(&cp[12]);
+ if (cp) glColor4ubv(&cp[12]);
glVertex3fv(b);
- if (cp) glColor3ubv(&cp[0]);
+ if (cp) glColor4ubv(&cp[0]);
glVertex3fv(a);
if (cp) cp += 16;
@@ -4414,7 +4421,8 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
if (!ob->sculpt)
return NULL;
- grid_pbvh = ccgDM_use_grid_pbvh(ccgdm);
+ /* In vwpaint, we always use a grid_pbvh for multires/subsurf */
+ grid_pbvh = (!(ob->mode & OB_MODE_SCULPT) || ccgDM_use_grid_pbvh(ccgdm));
if (ob->sculpt->pbvh) {
if (grid_pbvh) {
@@ -4430,12 +4438,18 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
ccgdm->pbvh = ob->sculpt->pbvh;
}
- if (ccgdm->pbvh)
+ if (ccgdm->pbvh) {
+ /* For vertex paint, keep track of ccgdm */
+ if (!(ob->mode & OB_MODE_SCULPT)) {
+ BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm);
+ }
return ccgdm->pbvh;
+ }
/* no pbvh exists yet, we need to create one. only in case of multires
* we build a pbvh over the modified mesh, in other cases the base mesh
* is being sculpted, so we build a pbvh from that. */
+ /* Note: vwpaint always builds a pbvh over the modified mesh. */
if (grid_pbvh) {
ccgdm_create_grids(dm);
@@ -4466,6 +4480,10 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
if (ccgdm->pbvh)
pbvh_show_diffuse_color_set(ccgdm->pbvh, ob->sculpt->show_diffuse_color);
+ /* For vertex paint, keep track of ccgdm */
+ if (!(ob->mode & OB_MODE_SCULPT) && ccgdm->pbvh) {
+ BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm);
+ }
return ccgdm->pbvh;
}
@@ -4474,47 +4492,39 @@ static void ccgDM_recalcTessellation(DerivedMesh *UNUSED(dm))
/* Nothing to do: CCG handles creating its own tessfaces */
}
-static void ccgDM_recalcLoopTri(DerivedMesh *UNUSED(dm))
-{
- /* Nothing to do: CCG tessellation is known,
- * allocate and fill in with ccgDM_getLoopTriArray */
-}
-
-static const MLoopTri *ccgDM_getLoopTriArray(DerivedMesh *dm)
+/* WARNING! *MUST* be called in an 'loops_cache_rwlock' protected thread context! */
+static void ccgDM_recalcLoopTri(DerivedMesh *dm)
{
- BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE);
- if (dm->looptris.array) {
- BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
- }
- else {
- MLoopTri *mlooptri;
- const int tottri = dm->numPolyData * 2;
- int i, poly_index;
-
- DM_ensure_looptri_data(dm);
- mlooptri = dm->looptris.array;
-
- BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
- BLI_assert(tottri == dm->looptris.num);
-
- for (i = 0, poly_index = 0; i < tottri; i += 2, poly_index += 1) {
- MLoopTri *lt;
- lt = &mlooptri[i];
- /* quad is (0, 3, 2, 1) */
- lt->tri[0] = (poly_index * 4) + 0;
- lt->tri[1] = (poly_index * 4) + 2;
- lt->tri[2] = (poly_index * 4) + 3;
- lt->poly = poly_index;
-
- lt = &mlooptri[i + 1];
- lt->tri[0] = (poly_index * 4) + 0;
- lt->tri[1] = (poly_index * 4) + 1;
- lt->tri[2] = (poly_index * 4) + 2;
- lt->poly = poly_index;
- }
- }
- BLI_rw_mutex_unlock(&loops_cache_rwlock);
- return dm->looptris.array;
+ MLoopTri *mlooptri = dm->looptris.array;
+ const int tottri = dm->numPolyData * 2;
+ int i, poly_index;
+
+ DM_ensure_looptri_data(dm);
+ mlooptri = dm->looptris.array_wip;
+
+ BLI_assert(tottri == 0 || mlooptri != NULL);
+ BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
+ BLI_assert(tottri == dm->looptris.num);
+
+ for (i = 0, poly_index = 0; i < tottri; i += 2, poly_index += 1) {
+ MLoopTri *lt;
+ lt = &mlooptri[i];
+ /* quad is (0, 3, 2, 1) */
+ lt->tri[0] = (poly_index * 4) + 0;
+ lt->tri[1] = (poly_index * 4) + 2;
+ lt->tri[2] = (poly_index * 4) + 3;
+ lt->poly = poly_index;
+
+ lt = &mlooptri[i + 1];
+ lt->tri[0] = (poly_index * 4) + 0;
+ lt->tri[1] = (poly_index * 4) + 1;
+ lt->tri[2] = (poly_index * 4) + 2;
+ lt->poly = poly_index;
+ }
+
+ BLI_assert(dm->looptris.array == NULL);
+ atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip);
+ dm->looptris.array_wip = NULL;
}
static void ccgDM_calcNormals(DerivedMesh *dm)
@@ -4533,8 +4543,6 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm)
ccgdm->dm.getNumPolys = ccgDM_getNumPolys;
ccgdm->dm.getNumTessFaces = ccgDM_getNumTessFaces;
- ccgdm->dm.getLoopTriArray = ccgDM_getLoopTriArray;
-
ccgdm->dm.getVert = ccgDM_getFinalVert;
ccgdm->dm.getEdge = ccgDM_getFinalEdge;
ccgdm->dm.getTessFace = ccgDM_getFinalFace;
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 1636042f479..7c4aa81ee46 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -224,7 +224,7 @@ Text *BKE_text_add(Main *bmain, const char *name)
{
Text *ta;
- ta = BKE_libblock_alloc(bmain, ID_TXT, name);
+ ta = BKE_libblock_alloc(bmain, ID_TXT, name, 0);
BKE_text_init(ta);
@@ -235,8 +235,9 @@ Text *BKE_text_add(Main *bmain, const char *name)
/* to a valid utf-8 sequences */
int txt_extended_ascii_as_utf8(char **str)
{
- int bad_char, added = 0, i = 0;
- int length = strlen(*str);
+ ptrdiff_t bad_char, i = 0;
+ const ptrdiff_t length = (ptrdiff_t)strlen(*str);
+ int added = 0;
while ((*str)[i]) {
if ((bad_char = BLI_utf8_invalid_byte(*str + i, length - i)) == -1)
@@ -248,7 +249,7 @@ int txt_extended_ascii_as_utf8(char **str)
if (added != 0) {
char *newstr = MEM_mallocN(length + added + 1, "text_line");
- int mi = 0;
+ ptrdiff_t mi = 0;
i = 0;
while ((*str)[i]) {
@@ -409,7 +410,8 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
return false;
}
- ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs));
+ ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs), 0);
+ ta->id.us = 0;
BLI_listbase_clear(&ta->lines);
ta->curl = ta->sell = NULL;
@@ -447,53 +449,49 @@ Text *BKE_text_load(Main *bmain, const char *file, const char *relpath)
return BKE_text_load_ex(bmain, file, relpath, false);
}
-Text *BKE_text_copy(Main *bmain, Text *ta)
+/**
+ * Only copy internal data of Text ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_text_copy_data(Main *UNUSED(bmain), Text *ta_dst, const Text *ta_src, const int UNUSED(flag))
{
- Text *tan;
- TextLine *line, *tmp;
-
- tan = BKE_libblock_copy(bmain, &ta->id);
-
/* file name can be NULL */
- if (ta->name) {
- tan->name = BLI_strdup(ta->name);
- }
- else {
- tan->name = NULL;
+ if (ta_src->name) {
+ ta_dst->name = BLI_strdup(ta_src->name);
}
- tan->flags = ta->flags | TXT_ISDIRTY;
-
- BLI_listbase_clear(&tan->lines);
- tan->curl = tan->sell = NULL;
- tan->compiled = NULL;
-
- tan->nlines = ta->nlines;
+ ta_dst->flags |= TXT_ISDIRTY;
+
+ BLI_listbase_clear(&ta_dst->lines);
+ ta_dst->curl = ta_dst->sell = NULL;
+ ta_dst->compiled = NULL;
- line = ta->lines.first;
/* Walk down, reconstructing */
- while (line) {
- tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line = MEM_mallocN(line->len + 1, "textline_string");
- tmp->format = NULL;
-
- strcpy(tmp->line, line->line);
+ for (TextLine *line_src = ta_src->lines.first; line_src; line_src = line_src->next) {
+ TextLine *line_dst = MEM_mallocN(sizeof(*line_dst), __func__);
- tmp->len = line->len;
-
- BLI_addtail(&tan->lines, tmp);
-
- line = line->next;
- }
+ line_dst->line = BLI_strdup(line_src->line);
+ line_dst->format = NULL;
+ line_dst->len = line_src->len;
- tan->curl = tan->sell = tan->lines.first;
- tan->curc = tan->selc = 0;
+ BLI_addtail(&ta_dst->lines, line_dst);
+ }
- init_undo_text(tan);
+ ta_dst->curl = ta_dst->sell = ta_dst->lines.first;
+ ta_dst->curc = ta_dst->selc = 0;
- BKE_id_copy_ensure_local(bmain, &ta->id, &tan->id);
+ init_undo_text(ta_dst);
+}
- return tan;
+Text *BKE_text_copy(Main *bmain, const Text *ta)
+{
+ Text *ta_copy;
+ BKE_id_copy_ex(bmain, &ta->id, (ID **)&ta_copy, 0, false);
+ return ta_copy;
}
void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local)
@@ -1933,7 +1931,7 @@ void txt_do_undo(Text *text)
int op = text->undo_buf[text->undo_pos];
int prev_flags;
unsigned int linep;
- unsigned int uchar;
+ unsigned int uni_char;
unsigned int curln, selln;
unsigned short curc, selc;
unsigned short charp;
@@ -1969,14 +1967,14 @@ void txt_do_undo(Text *text)
case UNDO_BS_3:
case UNDO_BS_4:
charp = op - UNDO_BS_1 + 1;
- uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
/* get and restore the cursors */
txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
- txt_add_char(text, uchar);
+ txt_add_char(text, uni_char);
text->undo_pos--;
break;
@@ -1986,14 +1984,14 @@ void txt_do_undo(Text *text)
case UNDO_DEL_3:
case UNDO_DEL_4:
charp = op - UNDO_DEL_1 + 1;
- uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
/* get and restore the cursors */
txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
- txt_add_char(text, uchar);
+ txt_add_char(text, uni_char);
txt_move_left(text, 0);
@@ -2161,7 +2159,7 @@ void txt_do_redo(Text *text)
char *buf;
unsigned int linep;
unsigned short charp;
- unsigned int uchar;
+ unsigned int uni_uchar;
unsigned int curln, selln;
unsigned short curc, selc;
@@ -2188,9 +2186,9 @@ void txt_do_redo(Text *text)
txt_move_to(text, curln, curc, 1);
charp = op - UNDO_INSERT_1 + 1;
- uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp);
- txt_add_char(text, uchar);
+ txt_add_char(text, uni_uchar);
break;
case UNDO_BS_1:
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 2d3ecad19ad..8f0334a4752 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -549,11 +549,11 @@ int colorband_element_remove(struct ColorBand *coba, int index)
if (index < 0 || index >= coba->tot)
return 0;
+ coba->tot--;
for (a = index; a < coba->tot; a++) {
coba->data[a] = coba->data[a + 1];
}
if (coba->cur) coba->cur--;
- coba->tot--;
return 1;
}
@@ -707,7 +707,7 @@ Tex *BKE_texture_add(Main *bmain, const char *name)
{
Tex *tex;
- tex = BKE_libblock_alloc(bmain, ID_TE, name);
+ tex = BKE_libblock_alloc(bmain, ID_TE, name, 0);
BKE_texture_default(tex);
@@ -846,41 +846,71 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
/* ------------------------------------------------------------------------- */
-Tex *BKE_texture_copy(Main *bmain, Tex *tex)
+/**
+ * Only copy internal data of Texture ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const int flag)
{
- Tex *texn;
-
- texn = BKE_libblock_copy(bmain, &tex->id);
- if (BKE_texture_is_image_user(tex)) {
- id_us_plus((ID *)texn->ima);
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+
+ if (!BKE_texture_is_image_user(tex_src)) {
+ tex_dst->ima = NULL;
}
- else {
- texn->ima = NULL;
+
+ if (tex_dst->coba) {
+ tex_dst->coba = MEM_dupallocN(tex_dst->coba);
+ }
+ if (tex_dst->env) {
+ tex_dst->env = BKE_texture_envmap_copy(tex_dst->env, flag_subdata);
+ }
+ if (tex_dst->pd) {
+ tex_dst->pd = BKE_texture_pointdensity_copy(tex_dst->pd, flag_subdata);
+ }
+ if (tex_dst->vd) {
+ tex_dst->vd = MEM_dupallocN(tex_dst->vd);
+ }
+ if (tex_dst->ot) {
+ tex_dst->ot = BKE_texture_ocean_copy(tex_dst->ot, flag_subdata);
}
-
- if (texn->coba) texn->coba = MEM_dupallocN(texn->coba);
- if (texn->env) texn->env = BKE_texture_envmap_copy(texn->env);
- if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd);
- if (texn->vd) texn->vd = MEM_dupallocN(texn->vd);
- if (texn->ot) texn->ot = BKE_texture_ocean_copy(texn->ot);
- if (tex->nodetree) {
- if (tex->nodetree->execdata) {
- ntreeTexEndExecTree(tex->nodetree->execdata);
+ if (tex_src->nodetree) {
+ if (tex_src->nodetree->execdata) {
+ ntreeTexEndExecTree(tex_src->nodetree->execdata);
}
- texn->nodetree = ntreeCopyTree(bmain, tex->nodetree);
+ BKE_id_copy_ex(bmain, (ID *)tex_src->nodetree, (ID **)&tex_dst->nodetree, flag, false);
}
- BKE_previewimg_id_copy(&texn->id, &tex->id);
-
- BKE_id_copy_ensure_local(bmain, &tex->id, &texn->id);
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&tex_dst->id, &tex_src->id);
+ }
+ else {
+ tex_dst->preview = NULL;
+ }
+}
- return texn;
+Tex *BKE_texture_copy(Main *bmain, const Tex *tex)
+{
+ Tex *tex_copy;
+ BKE_id_copy_ex(bmain, &tex->id, (ID **)&tex_copy, 0, false);
+ return tex_copy;
}
/* texture copy without adding to main dbase */
Tex *BKE_texture_localize(Tex *tex)
{
+ /* TODO replace with something like
+ * Tex *tex_copy;
+ * BKE_id_copy_ex(bmain, &tex->id, (ID **)&tex_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false);
+ * return tex_copy;
+ *
+ * ... Once f*** nodes are fully converted to that too :( */
+
Tex *texn;
texn = BKE_libblock_copy_nolib(&tex->id, false);
@@ -889,17 +919,17 @@ Tex *BKE_texture_localize(Tex *tex)
if (texn->coba) texn->coba = MEM_dupallocN(texn->coba);
if (texn->env) {
- texn->env = BKE_texture_envmap_copy(texn->env);
+ texn->env = BKE_texture_envmap_copy(texn->env, LIB_ID_CREATE_NO_USER_REFCOUNT);
id_us_min(&texn->env->ima->id);
}
- if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd);
+ if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd, LIB_ID_CREATE_NO_USER_REFCOUNT);
if (texn->vd) {
texn->vd = MEM_dupallocN(texn->vd);
if (texn->vd->dataset)
texn->vd->dataset = MEM_dupallocN(texn->vd->dataset);
}
if (texn->ot) {
- texn->ot = BKE_texture_ocean_copy(tex->ot);
+ texn->ot = BKE_texture_ocean_copy(tex->ot, LIB_ID_CREATE_NO_USER_REFCOUNT);
}
texn->preview = NULL;
@@ -1099,6 +1129,8 @@ void set_active_mtex(ID *id, short act)
case ID_PA:
((ParticleSettings *)id)->texact = act;
break;
+ default:
+ break;
}
}
@@ -1263,16 +1295,20 @@ EnvMap *BKE_texture_envmap_add(void)
/* ------------------------------------------------------------------------- */
-EnvMap *BKE_texture_envmap_copy(EnvMap *env)
+EnvMap *BKE_texture_envmap_copy(const EnvMap *env, const int flag)
{
EnvMap *envn;
int a;
envn = MEM_dupallocN(env);
envn->ok = 0;
- for (a = 0; a < 6; a++) envn->cube[a] = NULL;
- if (envn->ima) id_us_plus((ID *)envn->ima);
-
+ for (a = 0; a < 6; a++) {
+ envn->cube[a] = NULL;
+ }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)envn->ima);
+ }
+
return envn;
}
@@ -1336,14 +1372,16 @@ PointDensity *BKE_texture_pointdensity_add(void)
return pd;
}
-PointDensity *BKE_texture_pointdensity_copy(PointDensity *pd)
+PointDensity *BKE_texture_pointdensity_copy(const PointDensity *pd, const int UNUSED(flag))
{
PointDensity *pdn;
pdn = MEM_dupallocN(pd);
pdn->point_tree = NULL;
pdn->point_data = NULL;
- if (pdn->coba) pdn->coba = MEM_dupallocN(pdn->coba);
+ if (pdn->coba) {
+ pdn->coba = MEM_dupallocN(pdn->coba);
+ }
pdn->falloff_curve = curvemapping_copy(pdn->falloff_curve); /* can be NULL */
return pdn;
}
@@ -1430,7 +1468,7 @@ OceanTex *BKE_texture_ocean_add(void)
return ot;
}
-OceanTex *BKE_texture_ocean_copy(struct OceanTex *ot)
+OceanTex *BKE_texture_ocean_copy(const OceanTex *ot, const int UNUSED(flag))
{
OceanTex *otn = MEM_dupallocN(ot);
@@ -1485,9 +1523,11 @@ bool BKE_texture_dependsOnTime(const struct Tex *texture)
/* ------------------------------------------------------------------------- */
-void BKE_texture_get_value(
+void BKE_texture_get_value_ex(
const Scene *scene, Tex *texture,
- float *tex_co, TexResult *texres, bool use_color_management)
+ float *tex_co, TexResult *texres,
+ struct ImagePool *pool,
+ bool use_color_management)
{
int result_type;
bool do_color_manage = false;
@@ -1497,7 +1537,7 @@ void BKE_texture_get_value(
}
/* no node textures for now */
- result_type = multitex_ext_safe(texture, tex_co, texres, NULL, do_color_manage, false);
+ result_type = multitex_ext_safe(texture, tex_co, texres, pool, do_color_manage, false);
/* if the texture gave an RGB value, we assume it didn't give a valid
* intensity, since this is in the context of modifiers don't use perceptual color conversion.
@@ -1510,3 +1550,40 @@ void BKE_texture_get_value(
copy_v3_fl(&texres->tr, texres->tin);
}
}
+
+void BKE_texture_get_value(
+ const Scene *scene, Tex *texture,
+ float *tex_co, TexResult *texres, bool use_color_management)
+{
+ BKE_texture_get_value_ex(scene, texture, tex_co, texres, NULL, use_color_management);
+}
+
+static void texture_nodes_fetch_images_for_pool(bNodeTree *ntree, struct ImagePool *pool)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_IMAGE && node->id != NULL) {
+ Image *image = (Image *)node->id;
+ BKE_image_pool_acquire_ibuf(image, NULL, pool);
+ }
+ else if (node->type == NODE_GROUP && node->id != NULL) {
+ /* TODO(sergey): Do we need to control recursion here? */
+ bNodeTree *nested_tree = (bNodeTree *)node->id;
+ texture_nodes_fetch_images_for_pool(nested_tree, pool);
+ }
+ }
+}
+
+/* Make sure all images used by texture are loaded into pool. */
+void BKE_texture_fetch_images_for_pool(Tex *texture, struct ImagePool *pool)
+{
+ if (texture->nodetree != NULL) {
+ texture_nodes_fetch_images_for_pool(texture->nodetree, pool);
+ }
+ else {
+ if (texture->type == TEX_IMAGE) {
+ if (texture->ima != NULL) {
+ BKE_image_pool_acquire_ibuf(texture->ima, NULL, pool);
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 96ab8693122..b4ef381534f 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -49,8 +49,8 @@
#include "BLI_math.h"
#include "BLI_math_base.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
@@ -190,7 +190,7 @@ void BKE_tracking_free(MovieTracking *tracking)
}
/* Copy the whole list of tracks. */
-static void tracking_tracks_copy(ListBase *tracks_dst, ListBase *tracks_src, GHash *tracks_mapping)
+static void tracking_tracks_copy(ListBase *tracks_dst, const ListBase *tracks_src, GHash *tracks_mapping, const int flag)
{
MovieTrackingTrack *track_dst, *track_src;
@@ -202,7 +202,9 @@ static void tracking_tracks_copy(ListBase *tracks_dst, ListBase *tracks_src, GHa
if (track_src->markers) {
track_dst->markers = MEM_dupallocN(track_src->markers);
}
- id_us_plus(&track_dst->gpd->id);
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(&track_dst->gpd->id);
+ }
BLI_addtail(tracks_dst, track_dst);
BLI_ghash_insert(tracks_mapping, track_src, track_dst);
}
@@ -210,7 +212,8 @@ static void tracking_tracks_copy(ListBase *tracks_dst, ListBase *tracks_src, GHa
/* copy the whole list of plane tracks (need whole MovieTracking structures due to embedded pointers to tracks).
* WARNING: implies tracking_[dst/src] and their tracks have already been copied. */
-static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, ListBase *plane_tracks_src, GHash *tracks_mapping)
+static void tracking_plane_tracks_copy(
+ ListBase *plane_tracks_dst, const ListBase *plane_tracks_src, GHash *tracks_mapping, const int flag)
{
MovieTrackingPlaneTrack *plane_track_dst, *plane_track_src;
@@ -225,14 +228,17 @@ static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, ListBase *pla
for (int i = 0; i < plane_track_dst->point_tracksnr; i++) {
plane_track_dst->point_tracks[i] = BLI_ghash_lookup(tracks_mapping, plane_track_src->point_tracks[i]);
}
- id_us_plus(&plane_track_dst->image->id);
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(&plane_track_dst->image->id);
+ }
BLI_addtail(plane_tracks_dst, plane_track_dst);
}
}
/* Copy reconstruction structure. */
static void tracking_reconstruction_copy(
- MovieTrackingReconstruction *reconstruction_dst, MovieTrackingReconstruction *reconstruction_src)
+ MovieTrackingReconstruction *reconstruction_dst, const MovieTrackingReconstruction *reconstruction_src,
+ const int UNUSED(flag))
{
*reconstruction_dst = *reconstruction_src;
if (reconstruction_src->cameras) {
@@ -242,23 +248,25 @@ static void tracking_reconstruction_copy(
/* Copy stabilization structure. */
static void tracking_stabilization_copy(
- MovieTrackingStabilization *stabilization_dst, MovieTrackingStabilization *stabilization_src)
+ MovieTrackingStabilization *stabilization_dst, const MovieTrackingStabilization *stabilization_src,
+ const int UNUSED(flag))
{
*stabilization_dst = *stabilization_src;
}
/* Copy tracking object. */
static void tracking_object_copy(
- MovieTrackingObject *object_dst, MovieTrackingObject *object_src, GHash *tracks_mapping)
+ MovieTrackingObject *object_dst, const MovieTrackingObject *object_src, GHash *tracks_mapping, const int flag)
{
*object_dst = *object_src;
- tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping);
- tracking_plane_tracks_copy(&object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping);
- tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction);
+ tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping, flag);
+ tracking_plane_tracks_copy(&object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping, flag);
+ tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction, flag);
}
/* Copy list of tracking objects. */
-static void tracking_objects_copy(ListBase *objects_dst, ListBase *objects_src, GHash *tracks_mapping)
+static void tracking_objects_copy(
+ ListBase *objects_dst, const ListBase *objects_src, GHash *tracks_mapping, const int flag)
{
MovieTrackingObject *object_dst, *object_src;
@@ -266,22 +274,22 @@ static void tracking_objects_copy(ListBase *objects_dst, ListBase *objects_src,
for (object_src = objects_src->first; object_src != NULL; object_src = object_src->next) {
object_dst = MEM_mallocN(sizeof(*object_dst), __func__);
- tracking_object_copy(object_dst, object_src, tracks_mapping);
+ tracking_object_copy(object_dst, object_src, tracks_mapping, flag);
BLI_addtail(objects_dst, object_dst);
}
}
/* Copy tracking structure content. */
-void BKE_tracking_copy(MovieTracking *tracking_dst, MovieTracking *tracking_src)
+void BKE_tracking_copy(MovieTracking *tracking_dst, const MovieTracking *tracking_src, const int flag)
{
GHash *tracks_mapping = BLI_ghash_ptr_new(__func__);
*tracking_dst = *tracking_src;
- tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping);
- tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping);
- tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction);
- tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization);
+ tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping, flag);
+ tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping, flag);
+ tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction, flag);
+ tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization, flag);
if (tracking_src->act_track) {
tracking_dst->act_track = BLI_ghash_lookup(tracks_mapping, tracking_src->act_track);
}
@@ -299,7 +307,7 @@ void BKE_tracking_copy(MovieTracking *tracking_dst, MovieTracking *tracking_src)
}
/* Warning! Will override tracks_mapping. */
- tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping);
+ tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping, flag);
/* Those remaining are runtime data, they will be reconstructed as needed, do not bother copying them. */
tracking_dst->dopesheet.ok = false;
@@ -974,8 +982,11 @@ static void track_mask_set_pixel_cb(int x, int x_end, int y, void *user_data)
}
static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height,
- MovieTrackingMarker *marker, bGPDlayer *layer,
- float *mask, int mask_width, int mask_height)
+ const float region_min[2],
+ bGPDlayer *layer,
+ float *mask,
+ int mask_width,
+ int mask_height)
{
bGPDframe *frame = layer->frames.first;
TrackMaskSetPixelData data;
@@ -994,8 +1005,8 @@ static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height
point = mask_points = MEM_callocN(2 * stroke->totpoints * sizeof(int),
"track mask rasterization points");
for (int i = 0; i < stroke->totpoints; i++, point += 2) {
- point[0] = (stroke_points[i].x - marker->search_min[0]) * frame_width;
- point[1] = (stroke_points[i].y - marker->search_min[1]) * frame_height;
+ point[0] = stroke_points[i].x * frame_width - region_min[0];
+ point[1] = stroke_points[i].y * frame_height - region_min[1];
}
/* TODO: add an option to control whether AA is enabled or not */
BLI_bitmap_draw_2d_poly_v2i_n(
@@ -1010,26 +1021,42 @@ static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height
}
}
-float *BKE_tracking_track_get_mask(int frame_width, int frame_height,
- MovieTrackingTrack *track, MovieTrackingMarker *marker)
+/* Region is in pixel space, relative to marker's center. */
+float *tracking_track_get_mask_for_region(int frame_width, int frame_height,
+ const float region_min[2],
+ const float region_max[2],
+ MovieTrackingTrack *track)
{
float *mask = NULL;
bGPDlayer *layer = track_mask_gpencil_layer_get(track);
- int mask_width, mask_height;
-
- mask_width = (marker->search_max[0] - marker->search_min[0]) * frame_width;
- mask_height = (marker->search_max[1] - marker->search_min[1]) * frame_height;
-
- if (layer) {
+ if (layer != NULL) {
+ const int mask_width = region_max[0] - region_min[0];
+ const int mask_height = region_max[1] - region_min[1];
mask = MEM_callocN(mask_width * mask_height * sizeof(float), "track mask");
-
- track_mask_gpencil_layer_rasterize(frame_width, frame_height, marker, layer,
- mask, mask_width, mask_height);
+ track_mask_gpencil_layer_rasterize(frame_width, frame_height,
+ region_min,
+ layer,
+ mask,
+ mask_width, mask_height);
}
-
return mask;
}
+float *BKE_tracking_track_get_mask(int frame_width, int frame_height,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker)
+{
+ /* Convert normalized space marker's search area to pixel-space region. */
+ const float region_min[2] = {marker->search_min[0] * frame_width,
+ marker->search_min[1] * frame_height};
+ const float region_max[2] = {marker->search_max[0] * frame_width,
+ marker->search_max[1] * frame_height};
+ return tracking_track_get_mask_for_region(frame_width, frame_height,
+ region_min,
+ region_max,
+ track);
+}
+
float BKE_tracking_track_get_weight_for_marker(MovieClip *clip, MovieTrackingTrack *track, MovieTrackingMarker *marker)
{
FCurve *weight_fcurve;
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 3b56ea271d0..30981ed8f23 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -36,8 +36,9 @@
#include "DNA_movieclip_types.h"
#include "DNA_object_types.h" /* SELECT */
-#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_threads.h"
#include "BLI_math.h"
#include "BKE_movieclip.h"
@@ -76,6 +77,9 @@ typedef struct AutoTrackContext {
int num_tracks; /* Number of tracks being tracked. */
AutoTrackOptions *options; /* Per-tracking track options. */
+ /* Array of all tracks, indexed by track_index. */
+ MovieTrackingTrack **tracks;
+
bool backwards;
bool sequence;
int first_frame;
@@ -306,8 +310,15 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
BLI_spin_init(&context->spin_lock);
+ int num_total_tracks = BLI_listbase_count(tracksbase);
+ context->tracks =
+ MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks,
+ "auto track pointers");
+
context->image_accessor =
- tracking_image_accessor_new(context->clips, 1, user->framenr);
+ tracking_image_accessor_new(context->clips, 1,
+ context->tracks, num_total_tracks,
+ user->framenr);
context->autotrack =
libmv_autoTrackNew(context->image_accessor->libmv_accessor);
@@ -361,6 +372,7 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
options->use_keyframe_match =
track->pattern_match == TRACK_MATCH_KEYFRAME;
}
+ context->tracks[track_index] = track;
++track_index;
}
@@ -369,7 +381,7 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
bool BKE_autotrack_context_step(AutoTrackContext *context)
{
- int frame_delta = context->backwards ? -1 : 1;
+ const int frame_delta = context->backwards ? -1 : 1;
bool ok = false;
int track;
@@ -383,67 +395,64 @@ bool BKE_autotrack_context_step(AutoTrackContext *context)
libmv_reference_marker,
libmv_tracked_marker;
libmv_TrackRegionResult libmv_result;
- int frame = BKE_movieclip_remap_scene_to_clip_frame(
- context->clips[options->clip_index],
- context->user.framenr);
- bool has_marker;
-
+ const int frame = BKE_movieclip_remap_scene_to_clip_frame(
+ context->clips[options->clip_index],
+ context->user.framenr);
BLI_spin_lock(&context->spin_lock);
- has_marker = libmv_autoTrackGetMarker(context->autotrack,
- options->clip_index,
- frame,
- options->track_index,
- &libmv_current_marker);
+ const bool has_marker = libmv_autoTrackGetMarker(context->autotrack,
+ options->clip_index,
+ frame,
+ options->track_index,
+ &libmv_current_marker);
BLI_spin_unlock(&context->spin_lock);
-
- if (has_marker) {
- if (!tracking_check_marker_margin(&libmv_current_marker,
- options->track->margin,
- context->frame_width,
- context->frame_height))
- {
- continue;
- }
-
- libmv_tracked_marker = libmv_current_marker;
- libmv_tracked_marker.frame = frame + frame_delta;
-
- if (options->use_keyframe_match) {
- libmv_tracked_marker.reference_frame =
- libmv_current_marker.reference_frame;
- libmv_autoTrackGetMarker(context->autotrack,
- options->clip_index,
- libmv_tracked_marker.reference_frame,
- options->track_index,
- &libmv_reference_marker);
- }
- else {
- libmv_tracked_marker.reference_frame = frame;
- libmv_reference_marker = libmv_current_marker;
- }
-
- if (libmv_autoTrackMarker(context->autotrack,
- &options->track_region_options,
- &libmv_tracked_marker,
- &libmv_result))
- {
- BLI_spin_lock(&context->spin_lock);
- libmv_autoTrackAddMarker(context->autotrack,
- &libmv_tracked_marker);
- BLI_spin_unlock(&context->spin_lock);
- }
- else {
- options->is_failed = true;
- options->failed_frame = frame + frame_delta;
- }
- ok = true;
+ /* Check whether we've got marker to sync with. */
+ if (!has_marker) {
+ continue;
+ }
+ /* Check whether marker is going outside of allowed frame margin. */
+ if (!tracking_check_marker_margin(&libmv_current_marker,
+ options->track->margin,
+ context->frame_width,
+ context->frame_height))
+ {
+ continue;
}
+ libmv_tracked_marker = libmv_current_marker;
+ libmv_tracked_marker.frame = frame + frame_delta;
+ /* Update reference frame. */
+ if (options->use_keyframe_match) {
+ libmv_tracked_marker.reference_frame =
+ libmv_current_marker.reference_frame;
+ libmv_autoTrackGetMarker(context->autotrack,
+ options->clip_index,
+ libmv_tracked_marker.reference_frame,
+ options->track_index,
+ &libmv_reference_marker);
+ }
+ else {
+ libmv_tracked_marker.reference_frame = frame;
+ libmv_reference_marker = libmv_current_marker;
+ }
+ /* Perform actual tracking. */
+ if (libmv_autoTrackMarker(context->autotrack,
+ &options->track_region_options,
+ &libmv_tracked_marker,
+ &libmv_result))
+ {
+ BLI_spin_lock(&context->spin_lock);
+ libmv_autoTrackAddMarker(context->autotrack, &libmv_tracked_marker);
+ BLI_spin_unlock(&context->spin_lock);
+ }
+ else {
+ options->is_failed = true;
+ options->failed_frame = frame + frame_delta;
+ }
+ ok = true;
}
-
+ /* Advance the frame. */
BLI_spin_lock(&context->spin_lock);
context->user.framenr += frame_delta;
BLI_spin_unlock(&context->spin_lock);
-
return ok;
}
@@ -565,6 +574,7 @@ void BKE_autotrack_context_free(AutoTrackContext *context)
libmv_autoTrackDestroy(context->autotrack);
tracking_image_accessor_destroy(context->image_accessor);
MEM_freeN(context->options);
+ MEM_freeN(context->tracks);
BLI_spin_end(&context->spin_lock);
MEM_freeN(context);
}
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index b8949f9a0de..b8dfb217c16 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -203,7 +203,7 @@ static float get_animated_scaleinf(StabContext *ctx, int framenr)
static void get_animated_target_pos(StabContext *ctx,
int framenr,
- float target_pos[2])
+ float target_pos[2])
{
target_pos[0] = fetch_from_fcurve(ctx->target_pos[0],
framenr,
@@ -587,7 +587,7 @@ static void compensate_rotation_center(const int size, float aspect,
copy_v2_v2(intended_pivot, pivot);
copy_v2_v2(rotated_pivot, pivot);
- rotate_m2(rotation_mat, +angle);
+ angle_to_mat2(rotation_mat, +angle);
sub_v2_v2(rotated_pivot, origin);
mul_m2v2(rotation_mat, rotated_pivot);
mul_v2_fl(rotated_pivot, scale);
@@ -755,7 +755,8 @@ static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_
if (ok) {
r_ref_pos[0] /= weight_sum;
r_ref_pos[1] /= weight_sum;
- } else {
+ }
+ else {
/* No usable tracking data on any track on this frame.
* Use data from neighbouring frames to extrapolate...
*/
@@ -784,7 +785,8 @@ static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_
* Also default to this frame when we're in a gap */
average_marker_positions(ctx, next_lower, r_ref_pos);
- } else if (next_higher < MAXFRAME) {
+ }
+ else if (next_higher < MAXFRAME) {
average_marker_positions(ctx, next_higher, r_ref_pos);
}
use_values_from_fcurves(ctx, false);
@@ -967,7 +969,7 @@ static void initialize_track_for_stabilization(StabContext *ctx,
pos[0] *= aspect;
angle = average_angle - atan2f(pos[1],pos[0]);
- rotate_m2(local_data->stabilization_rotation_base, angle);
+ angle_to_mat2(local_data->stabilization_rotation_base, angle);
/* Per track baseline value for zoom. */
len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS;
@@ -1167,7 +1169,8 @@ static void stabilization_calculate_data(StabContext *ctx,
if (ctx->stab->flag & TRACKING_STABILIZE_SCALE) {
*r_scale = expf(scale_step * scaleinf); /* Averaged in log scale */
- } else {
+ }
+ else {
*r_scale = 1.0f;
}
@@ -1180,8 +1183,8 @@ static void stabilization_calculate_data(StabContext *ctx,
*/
get_animated_target_pos(ctx, framenr, target_pos);
sub_v2_v2(r_translation, target_pos);
- *r_angle -= get_animated_target_rot(ctx,framenr);
- target_scale = get_animated_target_scale(ctx,framenr);
+ *r_angle -= get_animated_target_rot(ctx, framenr);
+ target_scale = get_animated_target_scale(ctx, framenr);
if (target_scale != 0.0f) {
*r_scale /= target_scale;
/* target_scale is an expected/intended reference zoom value */
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index a90b1dee927..d8e98291117 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -42,8 +42,8 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_ghash.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -58,6 +58,15 @@
#include "libmv-capi.h"
+/* Uncomment this to have caching-specific debug prints. */
+// #define DEBUG_CACHE
+
+#ifdef DEBUG_CACHE
+# define CACHE_PRINTF(...) printf(__VA_ARGS__)
+#else
+# define CACHE_PRINTF(...)
+#endif
+
/*********************** Tracks map *************************/
TracksMap *tracks_map_new(const char *object_name, bool is_camera, int num_tracks, int customdata_size)
@@ -523,6 +532,8 @@ typedef struct AccessCacheKey {
int frame;
int downscale;
libmv_InputMode input_mode;
+ bool has_region;
+ float region_min[2], region_max[2];
int64_t transform_key;
} AccessCacheKey;
@@ -537,23 +548,44 @@ static bool accesscache_hashcmp(const void *a_v, const void *b_v)
{
const AccessCacheKey *a = (const AccessCacheKey *) a_v;
const AccessCacheKey *b = (const AccessCacheKey *) b_v;
-
-#define COMPARE_FIELD(field)
- { \
- if (a->clip_index != b->clip_index) { \
- return false; \
- } \
- } (void) 0
-
- COMPARE_FIELD(clip_index);
- COMPARE_FIELD(frame);
- COMPARE_FIELD(downscale);
- COMPARE_FIELD(input_mode);
- COMPARE_FIELD(transform_key);
-
-#undef COMPARE_FIELD
-
- return true;
+ if (a->clip_index != b->clip_index ||
+ a->frame != b->frame ||
+ a->downscale != b->downscale ||
+ a->input_mode != b->input_mode ||
+ a->has_region != b->has_region ||
+ a->transform_key != b->transform_key)
+ {
+ return true;
+ }
+ /* If there is region applied, compare it. */
+ if (a->has_region) {
+ if (!equals_v2v2(a->region_min, b->region_min) ||
+ !equals_v2v2(a->region_max, b->region_max))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void accesscache_construct_key(AccessCacheKey *key,
+ int clip_index,
+ int frame,
+ libmv_InputMode input_mode,
+ int downscale,
+ const libmv_Region *region,
+ int64_t transform_key)
+{
+ key->clip_index = clip_index;
+ key->frame = frame;
+ key->input_mode = input_mode;
+ key->downscale = downscale;
+ key->has_region = (region != NULL);
+ if (key->has_region) {
+ copy_v2_v2(key->region_min, region->min);
+ copy_v2_v2(key->region_max, region->max);
+ }
+ key->transform_key = transform_key;
}
static void accesscache_put(TrackingImageAccessor *accessor,
@@ -561,15 +593,13 @@ static void accesscache_put(TrackingImageAccessor *accessor,
int frame,
libmv_InputMode input_mode,
int downscale,
+ const libmv_Region *region,
int64_t transform_key,
ImBuf *ibuf)
{
AccessCacheKey key;
- key.clip_index = clip_index;
- key.frame = frame;
- key.input_mode = input_mode;
- key.downscale = downscale;
- key.transform_key = transform_key;
+ accesscache_construct_key(&key, clip_index, frame, input_mode, downscale,
+ region, transform_key);
IMB_moviecache_put(accessor->cache, &key, ibuf);
}
@@ -578,14 +608,12 @@ static ImBuf *accesscache_get(TrackingImageAccessor *accessor,
int frame,
libmv_InputMode input_mode,
int downscale,
+ const libmv_Region *region,
int64_t transform_key)
{
AccessCacheKey key;
- key.clip_index = clip_index;
- key.frame = frame;
- key.input_mode = input_mode;
- key.downscale = downscale;
- key.transform_key = transform_key;
+ accesscache_construct_key(&key, clip_index, frame, input_mode, downscale,
+ region, transform_key);
return IMB_moviecache_get(accessor->cache, &key);
}
@@ -625,17 +653,17 @@ static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf)
*/
size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float);
grayscale->channels = 1;
- if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image"))) {
+ if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
grayscale->mall |= IB_rectfloat;
grayscale->flags |= IB_rectfloat;
- }
- for (i = 0; i < grayscale->x * grayscale->y; ++i) {
- const float *pixel = ibuf->rect_float + ibuf->channels * i;
+ for (i = 0; i < grayscale->x * grayscale->y; ++i) {
+ const float *pixel = ibuf->rect_float + ibuf->channels * i;
- grayscale->rect_float[i] = 0.2126f * pixel[0] +
- 0.7152f * pixel[1] +
- 0.0722f * pixel[2];
+ grayscale->rect_float[i] = 0.2126f * pixel[0] +
+ 0.7152f * pixel[1] +
+ 0.0722f * pixel[2];
+ }
}
return grayscale;
@@ -653,14 +681,14 @@ static void ibuf_to_float_image(const ImBuf *ibuf, libmv_FloatImage *float_image
static ImBuf *float_image_to_ibuf(libmv_FloatImage *float_image)
{
ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0);
- size_t size = (size_t)ibuf->x * (size_t)ibuf->y *
- float_image->channels * sizeof(float);
+ size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float);
ibuf->channels = float_image->channels;
- if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image"))) {
+ if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
ibuf->mall |= IB_rectfloat;
ibuf->flags |= IB_rectfloat;
+
+ memcpy(ibuf->rect_float, float_image->buffer, size);
}
- memcpy(ibuf->rect_float, float_image->buffer, size);
return ibuf;
}
@@ -674,29 +702,37 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
{
ImBuf *ibuf, *orig_ibuf, *final_ibuf;
int64_t transform_key = 0;
-
if (transform != NULL) {
transform_key = libmv_frameAccessorgetTransformKey(transform);
}
-
/* First try to get fully processed image from the cache. */
+ BLI_spin_lock(&accessor->cache_lock);
ibuf = accesscache_get(accessor,
clip_index,
frame,
input_mode,
downscale,
+ region,
transform_key);
+ BLI_spin_unlock(&accessor->cache_lock);
if (ibuf != NULL) {
+ CACHE_PRINTF("Used cached buffer for frame %d\n", frame);
+ /* This is a little heuristic here: if we re-used image once, this is
+ * a high probability of the image to be related to a keyframe matched
+ * reference image. Those images we don't want to be thrown away because
+ * if we toss them out we'll be re-calculating them at the next
+ * iteration.
+ */
+ ibuf->userflags |= IB_PERSISTENT;
return ibuf;
}
-
+ CACHE_PRINTF("Calculate new buffer for frame %d\n", frame);
/* And now we do postprocessing of the original frame. */
orig_ibuf = accessor_get_preprocessed_ibuf(accessor, clip_index, frame);
-
if (orig_ibuf == NULL) {
return NULL;
}
-
+ /* Cut a region if requested. */
if (region != NULL) {
int width = region->max[0] - region->min[0],
height = region->max[1] - region->min[1];
@@ -756,7 +792,7 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
BLI_unlock_thread(LOCK_MOVIECLIP);
final_ibuf = orig_ibuf;
}
-
+ /* Downscale if needed. */
if (downscale > 0) {
if (final_ibuf == orig_ibuf) {
final_ibuf = IMB_dupImBuf(orig_ibuf);
@@ -765,7 +801,7 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
orig_ibuf->x / (1 << downscale),
orig_ibuf->y / (1 << downscale));
}
-
+ /* Apply possible transformation. */
if (transform != NULL) {
libmv_FloatImage input_image, output_image;
ibuf_to_float_image(final_ibuf, &input_image);
@@ -778,12 +814,13 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
final_ibuf = float_image_to_ibuf(&output_image);
libmv_floatImageDestroy(&output_image);
}
-
+ /* Transform number of channels. */
if (input_mode == LIBMV_IMAGE_MODE_RGBA) {
BLI_assert(orig_ibuf->channels == 3 || orig_ibuf->channels == 4);
/* pass */
}
else /* if (input_mode == LIBMV_IMAGE_MODE_MONO) */ {
+ BLI_assert(input_mode == LIBMV_IMAGE_MODE_MONO);
if (final_ibuf->channels != 1) {
ImBuf *grayscale_ibuf = make_grayscale_ibuf_copy(final_ibuf);
if (final_ibuf != orig_ibuf) {
@@ -793,37 +830,25 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
final_ibuf = grayscale_ibuf;
}
}
-
- /* it's possible processing still didn't happen at this point,
+ /* It's possible processing still didn't happen at this point,
* but we really need a copy of the buffer to be transformed
* and to be put to the cache.
*/
if (final_ibuf == orig_ibuf) {
final_ibuf = IMB_dupImBuf(orig_ibuf);
}
-
IMB_freeImBuf(orig_ibuf);
-
- /* We put postprocessed frame to the cache always for now,
- * not the smartest thing in the world, but who cares at this point.
- */
-
- /* TODO(sergey): Disable cache for now, because we don't store region
- * in the cache key and can't check whether cached version is usable for
- * us or not.
- *
- * Need to think better about what to cache and when.
- */
- if (false) {
- accesscache_put(accessor,
- clip_index,
- frame,
- input_mode,
- downscale,
- transform_key,
- final_ibuf);
- }
-
+ BLI_spin_lock(&accessor->cache_lock);
+ /* Put final buffer to cache. */
+ accesscache_put(accessor,
+ clip_index,
+ frame,
+ input_mode,
+ downscale,
+ region,
+ transform_key,
+ final_ibuf);
+ BLI_spin_unlock(&accessor->cache_lock);
return final_ibuf;
}
@@ -875,8 +900,64 @@ static void accessor_release_image_callback(libmv_CacheKey cache_key)
IMB_freeImBuf(ibuf);
}
+static libmv_CacheKey accessor_get_mask_for_track_callback(
+ libmv_FrameAccessorUserData *user_data,
+ int clip_index,
+ int frame,
+ int track_index,
+ const libmv_Region *region,
+ float **r_destination,
+ int *r_width,
+ int *r_height)
+{
+ /* Perform sanity checks first. */
+ TrackingImageAccessor *accessor = (TrackingImageAccessor *) user_data;
+ BLI_assert(clip_index < accessor->num_clips);
+ BLI_assert(track_index < accessor->num_tracks);
+ MovieTrackingTrack *track = accessor->tracks[track_index];
+ /* Early output, track does not use mask. */
+ if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) == 0) {
+ return NULL;
+ }
+ MovieClip *clip = accessor->clips[clip_index];
+ /* Construct fake user so we can access movie clip. */
+ MovieClipUser user;
+ int scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, frame);
+ BKE_movieclip_user_set_frame(&user, scene_frame);
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ user.render_flag = 0;
+ /* Get frame width and height so we can convert stroke coordinates
+ * and other things from normalized to pixel space.
+ */
+ int frame_width, frame_height;
+ BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
+ /* Actual mask sampling. */
+ MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, frame);
+ const float region_min[2] = {region->min[0] - marker->pos[0] * frame_width,
+ region->min[1] - marker->pos[1] * frame_height};
+ const float region_max[2] = {region->max[0] - marker->pos[0] * frame_width,
+ region->max[1] - marker->pos[1] * frame_height};
+ *r_destination = tracking_track_get_mask_for_region(frame_width, frame_height,
+ region_min,
+ region_max,
+ track);
+ *r_width = region->max[0] - region->min[0];
+ *r_height = region->max[1] - region->min[1];
+ return *r_destination;
+}
+
+static void accessor_release_mask_callback(libmv_CacheKey cache_key)
+{
+ if (cache_key != NULL) {
+ float *mask = (float *)cache_key;
+ MEM_freeN(mask);
+ }
+}
+
TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP],
int num_clips,
+ MovieTrackingTrack **tracks,
+ int num_tracks,
int start_frame)
{
TrackingImageAccessor *accessor =
@@ -891,12 +972,18 @@ TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR
memcpy(accessor->clips, clips, num_clips * sizeof(MovieClip *));
accessor->num_clips = num_clips;
+ accessor->tracks = tracks;
+ accessor->num_tracks = num_tracks;
accessor->start_frame = start_frame;
accessor->libmv_accessor =
libmv_FrameAccessorNew((libmv_FrameAccessorUserData *) accessor,
accessor_get_image_callback,
- accessor_release_image_callback);
+ accessor_release_image_callback,
+ accessor_get_mask_for_track_callback,
+ accessor_release_mask_callback);
+
+ BLI_spin_init(&accessor->cache_lock);
return accessor;
}
@@ -905,5 +992,6 @@ void tracking_image_accessor_destroy(TrackingImageAccessor *accessor)
{
IMB_moviecache_free(accessor->cache);
libmv_FrameAccessorDestroy(accessor->libmv_accessor);
+ BLI_spin_end(&accessor->cache_lock);
MEM_freeN(accessor);
}
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index c0a373395dc..8606da0743b 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -372,6 +372,12 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, con
value_conv = value / unit->scalar;
+ /* Adjust precision to expected number of significant digits.
+ * Note that here, we shall not have to worry about very big/small numbers, units are expected to replace
+ * 'scientific notation' in those cases. */
+ prec -= integer_digits_d(value_conv);
+ CLAMP(prec, 0, 6);
+
/* Convert to a string */
len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv);
@@ -442,12 +448,15 @@ size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system
size_t i;
i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0');
+ prec -= integer_digits_d(value_a / unit_b->scalar) - integer_digits_d(value_b / unit_b->scalar);
+ prec = max_ii(prec, 0);
+
/* is there enough space for at least 1 char of the next unit? */
if (i + 2 < len_max) {
str[i++] = ' ';
/* use low precision since this is a smaller unit */
- i += unit_as_string(str + i, len_max - i, value_b, prec ? 1 : 0, usys, unit_b, '\0');
+ i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0');
}
return i;
}
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index caa9a1e357f..e79b06a44fe 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -112,43 +112,59 @@ World *add_world(Main *bmain, const char *name)
{
World *wrld;
- wrld = BKE_libblock_alloc(bmain, ID_WO, name);
+ wrld = BKE_libblock_alloc(bmain, ID_WO, name, 0);
BKE_world_init(wrld);
return wrld;
}
-World *BKE_world_copy(Main *bmain, World *wrld)
+/**
+ * Only copy internal data of World ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, const int flag)
{
- World *wrldn;
- int a;
-
- wrldn = BKE_libblock_copy(bmain, &wrld->id);
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a]) {
- wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), "BKE_world_copy");
- memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex));
- id_us_plus((ID *)wrldn->mtex[a]->tex);
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (wrld_src->mtex[a]) {
+ wrld_dst->mtex[a] = MEM_dupallocN(wrld_src->mtex[a]);
}
}
- if (wrld->nodetree) {
- wrldn->nodetree = ntreeCopyTree(bmain, wrld->nodetree);
+ if (wrld_src->nodetree) {
+ BKE_id_copy_ex(bmain, (ID *)wrld_src->nodetree, (ID **)&wrld_dst->nodetree, flag, false);
}
-
- BKE_previewimg_id_copy(&wrldn->id, &wrld->id);
- BLI_listbase_clear(&wrldn->gpumaterial);
+ BLI_listbase_clear(&wrld_dst->gpumaterial);
- BKE_id_copy_ensure_local(bmain, &wrld->id, &wrldn->id);
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&wrld_dst->id, &wrld_src->id);
+ }
+ else {
+ wrld_dst->preview = NULL;
+ }
+}
- return wrldn;
+World *BKE_world_copy(Main *bmain, const World *wrld)
+{
+ World *wrld_copy;
+ BKE_id_copy_ex(bmain, &wrld->id, (ID **)&wrld_copy, 0, false);
+ return wrld_copy;
}
World *localize_world(World *wrld)
{
+ /* TODO replace with something like
+ * World *wrld_copy;
+ * BKE_id_copy_ex(bmain, &wrld->id, (ID **)&wrld_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false);
+ * return wrld_copy;
+ *
+ * ... Once f*** nodes are fully converted to that too :( */
+
World *wrldn;
int a;
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index 89b2caa5ac7..2fb4ed03603 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -80,10 +80,6 @@ static void *context_create_avi(void);
static void context_free_avi(void *context_v);
#endif /* WITH_AVI */
-#ifdef WITH_QUICKTIME
-# include "quicktime_export.h"
-#endif
-
#ifdef WITH_FFMPEG
# include "BKE_writeffmpeg.h"
#endif
@@ -115,16 +111,6 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
#endif
/* do the platform specific handles */
-#ifdef WITH_QUICKTIME
- if (imtype == R_IMF_IMTYPE_QUICKTIME) {
- mh.start_movie = start_qt;
- mh.append_movie = append_qt;
- mh.end_movie = end_qt;
- mh.get_movie_path = filepath_qt;
- mh.context_create = context_create_qt;
- mh.context_free = context_free_qt;
- }
-#endif
#ifdef WITH_FFMPEG
if (ELEM(imtype, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, R_IMF_IMTYPE_THEORA)) {
mh.start_movie = BKE_ffmpeg_start;
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index b0ab6f707fa..a19e4142894 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -444,7 +444,7 @@ static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDi
param = strchr(name, ':');
if (param) {
- *param++ = 0;
+ *param++ = '\0';
}
switch (prop->type) {
@@ -568,7 +568,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
if (context->ffmpeg_crf >= 0) {
ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf);
- } else {
+ }
+ else {
c->bit_rate = context->ffmpeg_video_bitrate * 1000;
c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000;
c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000;
@@ -576,8 +577,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
}
if (context->ffmpeg_preset) {
- char const * preset_name;
- switch(context->ffmpeg_preset) {
+ char const *preset_name;
+ switch (context->ffmpeg_preset) {
case FFM_PRESET_ULTRAFAST: preset_name = "ultrafast"; break;
case FFM_PRESET_SUPERFAST: preset_name = "superfast"; break;
case FFM_PRESET_VERYFAST: preset_name = "veryfast"; break;
@@ -680,6 +681,7 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
/* xasp & yasp got float lately... */
st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q(((double) rd->xasp / (double) rd->yasp), 255);
+ st->avg_frame_rate = av_inv_q(c->time_base);
set_ffmpeg_properties(rd, c, "video", &opts);
@@ -1114,7 +1116,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData
BLI_make_existing_file(string);
- autosplit[0] = 0;
+ autosplit[0] = '\0';
if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
if (context) {
@@ -1137,7 +1139,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData
strcat(string, *exts);
}
else {
- *(string + strlen(string) - strlen(*fe)) = 0;
+ *(string + strlen(string) - strlen(*fe)) = '\0';
strcat(string, autosplit);
strcat(string, *fe);
}
@@ -1267,7 +1269,7 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
if (is_autosplit == false) {
if (context->audio_mixdown_device) {
AUD_Device_free(context->audio_mixdown_device);
- context->audio_mixdown_device = 0;
+ context->audio_mixdown_device = NULL;
}
}
#endif
@@ -1283,50 +1285,50 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
/* Close the video codec */
- if (context->video_stream && context->video_stream->codec) {
+ if (context->video_stream != NULL && context->video_stream->codec != NULL) {
avcodec_close(context->video_stream->codec);
PRINT("zero video stream %p\n", context->video_stream);
- context->video_stream = 0;
+ context->video_stream = NULL;
}
- if (context->audio_stream && context->audio_stream->codec) {
+ if (context->audio_stream != NULL && context->audio_stream->codec != NULL) {
avcodec_close(context->audio_stream->codec);
- context->audio_stream = 0;
+ context->audio_stream = NULL;
}
/* free the temp buffer */
- if (context->current_frame) {
+ if (context->current_frame != NULL) {
delete_picture(context->current_frame);
- context->current_frame = 0;
+ context->current_frame = NULL;
}
- if (context->outfile && context->outfile->oformat) {
+ if (context->outfile != NULL && context->outfile->oformat) {
if (!(context->outfile->oformat->flags & AVFMT_NOFILE)) {
avio_close(context->outfile->pb);
}
}
- if (context->outfile) {
+ if (context->outfile != NULL) {
avformat_free_context(context->outfile);
- context->outfile = 0;
+ context->outfile = NULL;
}
- if (context->audio_input_buffer) {
+ if (context->audio_input_buffer != NULL) {
av_free(context->audio_input_buffer);
- context->audio_input_buffer = 0;
+ context->audio_input_buffer = NULL;
}
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- if (context->audio_output_buffer) {
+ if (context->audio_output_buffer != NULL) {
av_free(context->audio_output_buffer);
- context->audio_output_buffer = 0;
+ context->audio_output_buffer = NULL;
}
#endif
- if (context->audio_deinterleave_buffer) {
+ if (context->audio_deinterleave_buffer != NULL) {
av_free(context->audio_deinterleave_buffer);
- context->audio_deinterleave_buffer = 0;
+ context->audio_deinterleave_buffer = NULL;
}
- if (context->img_convert_ctx) {
+ if (context->img_convert_ctx != NULL) {
sws_freeContext(context->img_convert_ctx);
- context->img_convert_ctx = 0;
+ context->img_convert_ctx = NULL;
}
}
@@ -1425,8 +1427,8 @@ static IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, con
int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char *str)
{
AVCodecContext c;
- const AVOption *o = 0;
- const AVOption *p = 0;
+ const AVOption *o = NULL;
+ const AVOption *p = NULL;
char name_[128];
char *name;
char *param;
@@ -1445,7 +1447,7 @@ int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char
param = strchr(name, ' ');
}
if (param) {
- *param++ = 0;
+ *param++ = '\0';
while (*param == ' ') param++;
}
diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c
index 212af76a7e8..4757186f546 100644
--- a/source/blender/blenkernel/intern/writeframeserver.c
+++ b/source/blender/blenkernel/intern/writeframeserver.c
@@ -268,11 +268,7 @@ int BKE_frameserver_loop(void *context_v, RenderData *rd, ReportList *UNUSED(rep
struct timeval tv;
struct sockaddr_in addr;
int len, rval;
-#ifdef FREE_WINDOWS
- int socklen;
-#else
unsigned int socklen;
-#endif
char buf[4096];
FrameserverContext *context = context_v;
diff --git a/source/blender/blenkernel/tracking_private.h b/source/blender/blenkernel/tracking_private.h
index 591ee4d0d01..07236fb2096 100644
--- a/source/blender/blenkernel/tracking_private.h
+++ b/source/blender/blenkernel/tracking_private.h
@@ -105,6 +105,13 @@ struct MovieTrackingMarker *tracking_get_keyframed_marker(
int current_frame,
bool backwards);
+/*********************** Masking *************************/
+
+float *tracking_track_get_mask_for_region(int frame_width, int frame_height,
+ const float region_min[2],
+ const float region_max[2],
+ MovieTrackingTrack *track);
+
/*********************** Frame accessr *************************/
struct libmv_FrameAccessor;
@@ -114,12 +121,17 @@ typedef struct TrackingImageAccessor {
struct MovieCache *cache;
struct MovieClip *clips[MAX_ACCESSOR_CLIP];
int num_clips;
+ struct MovieTrackingTrack **tracks;
+ int num_tracks;
int start_frame;
struct libmv_FrameAccessor *libmv_accessor;
+ SpinLock cache_lock;
} TrackingImageAccessor;
TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP],
int num_clips,
+ MovieTrackingTrack **tracks,
+ int num_tracks,
int start_frame);
void tracking_image_accessor_destroy(TrackingImageAccessor *accessor);
diff --git a/source/blender/blenlib/BLI_alloca.h b/source/blender/blenlib/BLI_alloca.h
index b44e6c66d2a..4fa69a24966 100644
--- a/source/blender/blenlib/BLI_alloca.h
+++ b/source/blender/blenlib/BLI_alloca.h
@@ -29,10 +29,6 @@
/* BLI_array_alloca / alloca */
-#if defined(__MINGW32__)
-# include <malloc.h> /* mingw needs for alloca() */
-#endif
-
#if defined(__GNUC__) || defined(__clang__)
#if defined(__cplusplus) && (__cplusplus > 199711L)
#define BLI_array_alloca(arr, realsize) \
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index c645ff06c00..3ffca818c0d 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -135,11 +135,12 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
#define BLI_array_append_ret(arr) \
(BLI_array_reserve(arr, 1), &arr[(_##arr##_count++)])
-#define BLI_array_free(arr) \
+#define BLI_array_free(arr) { \
if (arr && (char *)arr != _##arr##_static) { \
- BLI_array_fake_user(arr); \
- MEM_freeN(arr); \
- } (void)0
+ BLI_array_fake_user(arr); \
+ MEM_freeN(arr); \
+ } \
+} ((void)0)
#define BLI_array_pop(arr) ( \
(arr && _##arr##_count) ? \
diff --git a/source/blender/blenlib/BLI_compiler_attrs.h b/source/blender/blenlib/BLI_compiler_attrs.h
index f0d32670229..4c548654e33 100644
--- a/source/blender/blenlib/BLI_compiler_attrs.h
+++ b/source/blender/blenlib/BLI_compiler_attrs.h
@@ -92,4 +92,12 @@
# define ATTR_PRINTF_FORMAT(format_param, dots_param)
#endif
+/* Use to suppress '-Wimplicit-fallthrough' (in place of 'break'). */
+#if defined(__GNUC__) && (__GNUC__ >= 7) /* gcc7.0+ only */
+#define ATTR_FALLTHROUGH __attribute__((fallthrough))
+#else
+#define ATTR_FALLTHROUGH ((void)0)
+#endif
+
+
#endif /* __BLI_COMPILER_ATTRS_H__ */
diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h
index 8edbc25bcbc..0726e3bb343 100644
--- a/source/blender/blenlib/BLI_compiler_compat.h
+++ b/source/blender/blenlib/BLI_compiler_compat.h
@@ -32,11 +32,6 @@
# define alloca _alloca
#endif
-/* alloca is defined here for MinGW32 */
-#ifdef __MINGW32__
-# include <malloc.h>
-#endif
-
#if defined(__cplusplus) && ((__cplusplus >= 201103L) || defined(_MSC_VER))
# define HAS_CPP11_FEATURES
#endif
@@ -53,12 +48,7 @@ extern "C++" {
#if defined(_MSC_VER)
# define BLI_INLINE static __forceinline
#else
-# if (defined(__APPLE__) && defined(__ppc__))
-/* static inline __attribute__ here breaks osx ppc gcc42 build */
-# define BLI_INLINE static __attribute__((always_inline)) __attribute__((__unused__))
-# else
-# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__))
-# endif
+# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__))
#endif
#endif /* __BLI_COMPILER_COMPAT_H__ */
diff --git a/source/blender/blenlib/BLI_dial.h b/source/blender/blenlib/BLI_dial.h
index ad7680fe03e..71ab57bb61a 100644
--- a/source/blender/blenlib/BLI_dial.h
+++ b/source/blender/blenlib/BLI_dial.h
@@ -52,8 +52,8 @@
typedef struct Dial Dial;
-Dial *BLI_dial_initialize(float start_position[2], float threshold);
+Dial *BLI_dial_initialize(const float start_position[2], float threshold);
-float BLI_dial_angle(Dial *dial, float current_position[2]);
+float BLI_dial_angle(Dial *dial, const float current_position[2]);
#endif /* __BLI_DIAL_H__ */
diff --git a/source/blender/blenlib/BLI_dynlib.h b/source/blender/blenlib/BLI_dynlib.h
index 7d5eb888021..310db9ea051 100644
--- a/source/blender/blenlib/BLI_dynlib.h
+++ b/source/blender/blenlib/BLI_dynlib.h
@@ -34,7 +34,7 @@
typedef struct DynamicLibrary DynamicLibrary;
-DynamicLibrary *BLI_dynlib_open(char *name);
+DynamicLibrary *BLI_dynlib_open(const char *name);
void *BLI_dynlib_find_symbol(DynamicLibrary *lib, const char *symname);
char *BLI_dynlib_get_error_as_string(DynamicLibrary *lib);
void BLI_dynlib_close(DynamicLibrary *lib);
diff --git a/source/blender/blenlib/BLI_dynstr.h b/source/blender/blenlib/BLI_dynstr.h
index 7aa1c30e449..b26accc7f78 100644
--- a/source/blender/blenlib/BLI_dynstr.h
+++ b/source/blender/blenlib/BLI_dynstr.h
@@ -43,11 +43,14 @@
#include "BLI_compiler_attrs.h"
struct DynStr;
+struct MemArena;
/** The abstract DynStr type */
typedef struct DynStr DynStr;
DynStr *BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+DynStr *BLI_dynstr_new_memarena(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL();
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL();
@@ -56,8 +59,9 @@ void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format
int BLI_dynstr_get_len(DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
char *BLI_dynstr_get_cstring(DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-
void BLI_dynstr_get_cstring_ex(DynStr *__restrict ds, char *__restrict str) ATTR_NONNULL();
+
+void BLI_dynstr_clear(DynStr *ds) ATTR_NONNULL();
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL();
#endif /* __BLI_DYNSTR_H__ */
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 91d139c7085..5c1fa57886a 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -65,10 +65,8 @@ int BLI_create_symlink(const char *path, const char *to) ATTR_NONNULL();
/* keep in sync with the definition of struct direntry in BLI_fileops_types.h */
#ifdef WIN32
-# if defined(_MSC_VER) || defined(__MINGW64__)
+# if defined(_MSC_VER)
typedef struct _stat64 BLI_stat_t;
-# elif defined(__MINGW32__)
-typedef struct _stati64 BLI_stat_t;
# else
typedef struct _stat BLI_stat_t;
# endif
diff --git a/source/blender/blenlib/BLI_fileops_types.h b/source/blender/blenlib/BLI_fileops_types.h
index 0cf8c8ddb4a..0ffa3276f1f 100644
--- a/source/blender/blenlib/BLI_fileops_types.h
+++ b/source/blender/blenlib/BLI_fileops_types.h
@@ -35,7 +35,7 @@
#include <sys/stat.h>
-#if defined(WIN32) && !defined(FREE_WINDOWS)
+#if defined(WIN32)
typedef unsigned int mode_t;
#endif
@@ -50,10 +50,8 @@ struct direntry {
const char *relname;
const char *path;
#ifdef WIN32 /* keep in sync with the definition of BLI_stat_t in BLI_fileops.h */
-# if defined(_MSC_VER) || defined(__MINGW64__)
+# if defined(_MSC_VER)
struct _stat64 s;
-# elif defined(__MINGW32__)
- struct _stati64 s;
# else
struct _stat s;
# endif
diff --git a/source/blender/blenlib/BLI_fnmatch.h b/source/blender/blenlib/BLI_fnmatch.h
index f69f5b39869..06fa5048622 100644
--- a/source/blender/blenlib/BLI_fnmatch.h
+++ b/source/blender/blenlib/BLI_fnmatch.h
@@ -28,7 +28,7 @@
extern "C" {
#endif
-#if defined WIN32 && !defined _LIBC || defined __sun
+#if defined WIN32 && !defined _LIBC
#if defined(__cplusplus) || (defined(__STDC__) && __STDC__)
#undef __P
@@ -53,7 +53,7 @@ extern "C" {
#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
-#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined(_GNU_SOURCE) || defined(__SUNPRO_C)
+#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined(_GNU_SOURCE)
#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
@@ -72,7 +72,7 @@ extern int fnmatch __P((const char *__pattern, const char *__string,
# define _GNU_SOURCE
# endif
# include <fnmatch.h>
-#endif /* defined WIN32 && !defined _LIBC || defined __sun */
+#endif /* defined WIN32 && !defined _LIBC */
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 7e3a009ede8..b42a36a3567 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -43,7 +43,7 @@ extern "C" {
#ifndef GHASH_INTERNAL_API
# ifdef __GNUC__
# undef _GHASH_INTERNAL_ATTR
-# define _GHASH_INTERNAL_ATTR __attribute__ ((deprecated))
+# define _GHASH_INTERNAL_ATTR __attribute__ ((deprecated)) /* not deprecated, just private. */
# endif
#endif
@@ -90,6 +90,7 @@ void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfre
void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve);
void BLI_ghash_insert(GHash *gh, void *key, void *val);
bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+void *BLI_ghash_replace_key(GHash *gh, void *key);
void *BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default) ATTR_WARN_UNUSED_RESULT;
void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
@@ -167,6 +168,8 @@ unsigned int BLI_ghashutil_inthash_p_murmur(const void *ptr);
unsigned int BLI_ghashutil_inthash_p_simple(const void *ptr);
bool BLI_ghashutil_intcmp(const void *a, const void *b);
+size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b);
+
unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4]);
#define BLI_ghashutil_inthash_v4(key) ( \
@@ -246,6 +249,7 @@ void BLI_gset_insert(GSet *gh, void *key);
bool BLI_gset_add(GSet *gs, void *key);
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key);
bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp);
+void *BLI_gset_replace_key(GSet *gs, void *key);
bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp);
@@ -294,6 +298,25 @@ double BLI_ghash_calc_quality(GHash *gh);
double BLI_gset_calc_quality(GSet *gs);
#endif /* GHASH_INTERNAL_API */
+#define GHASH_FOREACH_BEGIN(type, var, what) \
+ do { \
+ GHashIterator gh_iter##var; \
+ GHASH_ITER(gh_iter##var, what) { \
+ type var = (type)(BLI_ghashIterator_getValue(&gh_iter##var)); \
+
+#define GHASH_FOREACH_END() \
+ } \
+ } while(0)
+
+#define GSET_FOREACH_BEGIN(type, var, what) \
+ do { \
+ GSetIterator gh_iter##var; \
+ GSET_ITER(gh_iter##var, what) { \
+ type var = (type)(BLI_gsetIterator_getKey(&gh_iter##var));
+
+#define GSET_FOREACH_END() \
+ } \
+ } while(0)
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h
new file mode 100644
index 00000000000..e849e5f8f61
--- /dev/null
+++ b/source/blender/blenlib/BLI_hash.h
@@ -0,0 +1,66 @@
+/*
+ * ***** 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_HASH_H__
+#define __BLI_HASH_H__
+
+/** \file BLI_hash.h
+ * \ingroup bli
+ */
+
+BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
+{
+#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+
+ unsigned int a, b, c;
+
+ a = b = c = 0xdeadbeef + (2 << 2) + 13;
+ a += kx;
+ b += ky;
+
+ c ^= b; c -= rot(b, 14);
+ a ^= c; a -= rot(c, 11);
+ b ^= a; b -= rot(a, 25);
+ c ^= b; c -= rot(b, 16);
+ a ^= c; a -= rot(c, 4);
+ b ^= a; b -= rot(a, 14);
+ c ^= b; c -= rot(b, 24);
+
+ return c;
+
+#undef rot
+}
+
+BLI_INLINE unsigned int BLI_hash_string(const char *str)
+{
+ unsigned int i = 0, c;
+
+ while ((c = *str++)) {
+ i = i * 37 + c;
+ }
+ return i;
+}
+
+BLI_INLINE unsigned int BLI_hash_int(unsigned int k)
+{
+ return BLI_hash_int_2d(k, 0);
+}
+
+#endif // __BLI_HASH_H__
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index 91d39801645..564659ad21e 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -36,7 +36,7 @@
*/
#ifdef __cplusplus
-extern "C" {
+extern "C" {
#endif
struct BVHTree;
@@ -62,7 +62,7 @@ typedef struct BVHTreeNearest {
int index; /* the index of the nearest found (untouched if none is found within a dist radius from the given coordinates) */
float co[3]; /* nearest coordinates (untouched it none is found within a dist radius from the given coordinates) */
float no[3]; /* normal at nearest coordinates (untouched it none is found within a dist radius from the given coordinates) */
- float dist_sq; /* squared distance to search arround */
+ float dist_sq; /* squared distance to search around */
int flags;
} BVHTreeNearest;
@@ -95,10 +95,6 @@ typedef void (*BVHTree_NearestPointCallback)(void *userdata, int index, const fl
/* callback must update hit in case it finds a nearest successful hit */
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, 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);
@@ -143,18 +139,6 @@ 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],
- const bool ray_is_normalized, const float scale[3],
- BVHTreeNearest *nearest,
- BVHTree_NearestToRayCallback callback, void *userdata);
-
int BLI_bvhtree_ray_cast_ex(
BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit,
BVHTree_RayCastCallback callback, void *userdata,
diff --git a/source/blender/blenlib/BLI_kdtree.h b/source/blender/blenlib/BLI_kdtree.h
index aa54e1c823c..18908f8c551 100644
--- a/source/blender/blenlib/BLI_kdtree.h
+++ b/source/blender/blenlib/BLI_kdtree.h
@@ -66,6 +66,10 @@ void BLI_kdtree_range_search_cb(
const KDTree *tree, const float co[3], float range,
bool (*search_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data);
+int BLI_kdtree_calc_duplicates_fast(
+ const KDTree *tree, const float range, bool use_index_order,
+ int *doubles);
+
/* Normal use is deprecated */
/* remove __normal functions when last users drop */
int BLI_kdtree_find_nearest_n__normal(
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 96349a7b066..b06944e4985 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -67,6 +67,7 @@ void *BLI_poptail(ListBase *listbase) ATTR_NONNULL(1);
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1);
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1);
+void BLI_insertlinkreplace(ListBase *listbase, void *v_l_src, void *v_l_dst) ATTR_NONNULL(1, 2, 3);
void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *)) ATTR_NONNULL(1, 2);
void BLI_listbase_sort_r(ListBase *listbase, int (*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1, 2);
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
@@ -124,6 +125,11 @@ if ((lb)->last && (lb_init || (lb_init = (lb)->last))) { \
(lb_iter != lb_init)); \
}
+#define LINKLIST_FOREACH(type, var, list) \
+ for (type var = (type)((list)->first); \
+ var != NULL; \
+ var = (type)(((Link*)(var))->next))
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index e97a250cd24..e6a72298ae7 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -85,63 +85,6 @@ static const int NAN_INT = 0x7FC00000;
# define NAN_FLT (*((float *)(&NAN_INT)))
#endif
-/* do not redefine functions from C99, POSIX.1-2001 or MSVC12 (partial C99) */
-#if !(defined(_ISOC99_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || defined(_MSC_VER))
-
-#ifndef sqrtf
-#define sqrtf(a) ((float)sqrt(a))
-#endif
-#ifndef powf
-#define powf(a, b) ((float)pow(a, b))
-#endif
-#ifndef cosf
-#define cosf(a) ((float)cos(a))
-#endif
-#ifndef sinf
-#define sinf(a) ((float)sin(a))
-#endif
-#ifndef acosf
-#define acosf(a) ((float)acos(a))
-#endif
-#ifndef asinf
-#define asinf(a) ((float)asin(a))
-#endif
-#ifndef atan2f
-#define atan2f(a, b) ((float)atan2(a, b))
-#endif
-#ifndef tanf
-#define tanf(a) ((float)tan(a))
-#endif
-#ifndef atanf
-#define atanf(a) ((float)atan(a))
-#endif
-#ifndef floorf
-#define floorf(a) ((float)floor(a))
-#endif
-#ifndef ceilf
-#define ceilf(a) ((float)ceil(a))
-#endif
-#ifndef fabsf
-#define fabsf(a) ((float)fabs(a))
-#endif
-#ifndef logf
-#define logf(a) ((float)log(a))
-#endif
-#ifndef expf
-#define expf(a) ((float)exp(a))
-#endif
-#ifndef fmodf
-#define fmodf(a, b) ((float)fmod(a, b))
-#endif
-#ifndef hypotf
-#define hypotf(a, b) ((float)hypot(a, b))
-#endif
-#ifndef copysignf
-#define copysignf(a, b) ((float)copysign(a, b))
-#endif
-
-#endif /* C99, POSIX.1-2001 or MSVC12 (partial C99) */
-
#if BLI_MATH_DO_INLINE
#include "intern/math_base_inline.c"
#endif
@@ -195,6 +138,9 @@ MINLINE int signum_i(float a);
MINLINE float power_of_2(float f);
+MINLINE int integer_digits_f(const float f);
+MINLINE int integer_digits_d(const double d);
+
/* these don't really fit anywhere but were being copied about a lot */
MINLINE int is_power_of_2_i(int n);
MINLINE int power_of_2_max_i(int n);
@@ -203,10 +149,37 @@ MINLINE int power_of_2_min_i(int n);
MINLINE unsigned int power_of_2_max_u(unsigned int x);
MINLINE unsigned int power_of_2_min_u(unsigned int x);
-MINLINE int iroundf(float a);
MINLINE int divide_round_i(int a, int b);
MINLINE int mod_i(int i, int n);
+MINLINE signed char round_fl_to_char(float a);
+MINLINE unsigned char round_fl_to_uchar(float a);
+MINLINE short round_fl_to_short(float a);
+MINLINE unsigned short round_fl_to_ushort(float a);
+MINLINE int round_fl_to_int(float a);
+MINLINE unsigned int round_fl_to_uint(float a);
+
+MINLINE signed char round_db_to_char(double a);
+MINLINE unsigned char round_db_to_uchar(double a);
+MINLINE short round_db_to_short(double a);
+MINLINE unsigned short round_db_to_ushort(double a);
+MINLINE int round_db_to_int(double a);
+MINLINE unsigned int round_db_to_uint(double a);
+
+MINLINE signed char round_fl_to_char_clamp(float a);
+MINLINE unsigned char round_fl_to_uchar_clamp(float a);
+MINLINE short round_fl_to_short_clamp(float a);
+MINLINE unsigned short round_fl_to_ushort_clamp(float a);
+MINLINE int round_fl_to_int_clamp(float a);
+MINLINE unsigned int round_fl_to_uint_clamp(float a);
+
+MINLINE signed char round_db_to_char_clamp(double a);
+MINLINE unsigned char round_db_to_uchar_clamp(double a);
+MINLINE short round_db_to_short_clamp(double a);
+MINLINE unsigned short round_db_to_ushort_clamp(double a);
+MINLINE int round_db_to_int_clamp(double a);
+MINLINE unsigned int round_db_to_uint_clamp(double a);
+
int pow_i(int base, int exp);
double double_round(double x, int ndigits);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 514b0300274..933e31ba84b 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -44,9 +44,6 @@ extern "C" {
/********************************** Polygons *********************************/
-void cent_tri_v3(float r[3], const float a[3], const float b[3], const float c[3]);
-void cent_quad_v3(float r[3], const float a[3], const float b[3], const float c[3], const float d[3]);
-
float normal_tri_v3(float r[3], const float a[3], const float b[3], const float c[3]);
float normal_quad_v3(float r[3], const float a[3], const float b[3], const float c[3], const float d[3]);
float normal_poly_v3(float r[3], const float verts[][3], unsigned int nr);
@@ -122,6 +119,26 @@ 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);
+
+struct DistRayAABB_Precalc {
+ float ray_origin[3];
+ float ray_direction[3];
+ float ray_inv_dir[3];
+ bool sign[3];
+};
+void dist_squared_ray_to_aabb_v3_precalc(
+ struct DistRayAABB_Precalc *neasrest_precalc,
+ const float ray_origin[3], const float ray_direction[3]);
+float dist_squared_ray_to_aabb_v3(
+ const struct DistRayAABB_Precalc *data,
+ const float bb_min[3], const float bb_max[3],
+ float r_point[3], float *r_depth);
+/* when there is no advantage to precalc. */
+float dist_squared_ray_to_aabb_v3_simple(
+ const float ray_origin[3], const float ray_direction[3],
+ const float bb_min[3], const float bb_max[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]);
@@ -169,8 +186,14 @@ void limit_dist_v3(float v1[3], float v2[3], const float dist);
int isect_seg_seg_v2(const float a1[2], const float a2[2], const float b1[2], const float b2[2]);
int isect_seg_seg_v2_int(const int a1[2], const int a2[2], const int b1[2], const int b2[2]);
-int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float vi[2]);
-bool isect_seg_seg_v2_simple(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
+int isect_seg_seg_v2_point_ex(
+ const float v0[2], const float v1[2], const float v2[2], const float v3[2], const float endpoint_bias,
+ float vi[2]);
+int isect_seg_seg_v2_point(
+ const float v0[2], const float v1[2], const float v2[2], const float v3[2],
+ float vi[2]);
+bool isect_seg_seg_v2_simple(
+ const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
int isect_line_sphere_v3(const float l1[3], const float l2[3], const float sp[3], const float r, float r_p1[3], float r_p2[3]);
int isect_line_sphere_v2(const float l1[2], const float l2[2], const float sp[2], const float r, float r_p1[2], float r_p2[2]);
@@ -296,23 +319,10 @@ void isect_ray_aabb_v3_precalc(
bool isect_ray_aabb_v3(
const struct IsectRayAABB_Precalc *data,
const float bb_min[3], const float bb_max[3], float *tmin);
-
-struct NearestRayToAABB_Precalc {
- float ray_origin[3];
- float ray_direction[3];
- float ray_inv_dir[3];
- float cdot_axis[3];
- float idiag_sq[3];
- bool sign[3];
-};
-
-void dist_squared_ray_to_aabb_v3_precalc(
- struct NearestRayToAABB_Precalc *data,
- const float ray_origin[3], const float ray_direction[3]);
-float dist_squared_ray_to_aabb_v3(
- const struct NearestRayToAABB_Precalc *data,
+bool isect_ray_aabb_v3_simple(
+ const float orig[3], const float dir[3],
const float bb_min[3], const float bb_max[3],
- bool r_axis_closest[3]);
+ float *tmin, float *tmax);
/* other */
bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const float radius,
@@ -326,10 +336,8 @@ bool clip_segment_v3_plane_n(
float r_p1[3], float r_p2[3]);
/****************************** Interpolation ********************************/
-
-/* tri or quad, d can be NULL */
-void interp_weights_face_v3(float w[4],
- const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]);
+void interp_weights_tri_v3(float w[3], const float a[3], const float b[3], const float c[3], const float p[3]);
+void interp_weights_quad_v3(float w[4], const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]);
void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]);
void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]);
@@ -394,26 +402,28 @@ void box_minmax_bounds_m4(float min[3], float max[3],
void map_to_tube(float *r_u, float *r_v, const float x, const float y, const float z);
void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const float z);
+void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3]);
+void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2], const float co[3], const float axis[3], const float angle);
/********************************** Normals **********************************/
-void accumulate_vertex_normals_tri(
+void accumulate_vertex_normals_tri_v3(
float n1[3], float n2[3], float n3[3],
const float f_no[3],
const float co1[3], const float co2[3], const float co3[3]);
-void accumulate_vertex_normals(
+void accumulate_vertex_normals_v3(
float n1[3], float n2[3], float n3[3], float n4[3],
const float f_no[3],
const float co1[3], const float co2[3], const float co3[3], const float co4[3]);
-void accumulate_vertex_normals_poly(
+void accumulate_vertex_normals_poly_v3(
float **vertnos, const float polyno[3],
const float **vertcos, float vdiffs[][3], const int nverts);
/********************************* Tangents **********************************/
-void tangent_from_uv(
+void tangent_from_uv_v3(
const float uv1[2], const float uv2[2], const float uv3[2],
const float co1[3], const float co2[3], const float co3[3],
const float n[3],
@@ -421,9 +431,9 @@ void tangent_from_uv(
/******************************** Vector Clouds ******************************/
-void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight,
- float (*rpos)[3], float *rweight,
- float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3]);
+void vcloud_estimate_transform_v3(
+ const int list_size, const float (*pos)[3], const float *weight, const float (*rpos)[3], const float *rweight,
+ float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3]);
/****************************** Spherical Harmonics *************************/
@@ -454,7 +464,7 @@ float form_factor_hemi_poly(float p[3], float n[3],
float v1[3], float v2[3], float v3[3], float v4[3]);
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3]);
-void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3]);
+void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3]);
MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3]);
MINLINE float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axis[3]) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_math_inline.h b/source/blender/blenlib/BLI_math_inline.h
index 840cf24f8cf..383abda5b2f 100644
--- a/source/blender/blenlib/BLI_math_inline.h
+++ b/source/blender/blenlib/BLI_math_inline.h
@@ -44,12 +44,7 @@ extern "C" {
# define MALWAYS_INLINE MINLINE
# else
# define MINLINE static inline
-# if (defined(__APPLE__) && defined(__ppc__))
- /* static inline __attribute__ here breaks osx ppc gcc42 build */
-# define MALWAYS_INLINE static __attribute__((always_inline)) __attribute__((unused))
-# else
-# define MALWAYS_INLINE static inline __attribute__((always_inline)) __attribute__((unused))
-# endif
+# define MALWAYS_INLINE static inline __attribute__((always_inline)) __attribute__((unused))
# endif
#else
# define MINLINE
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 8124e07dd47..d0dfad2a02f 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -219,7 +219,6 @@ void mat4_to_size(float r[3], float M[4][4]);
void translate_m4(float mat[4][4], float tx, float ty, float tz);
void rotate_m4(float mat[4][4], const char axis, const float angle);
-void rotate_m2(float mat[2][2], const float angle);
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3]);
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 24c20ee7b50..e059327a490 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -122,8 +122,9 @@ void mat3_to_axis_angle(float axis[3], float *angle, float M[3][3]);
void mat4_to_axis_angle(float axis[3], float *angle, float M[4][4]);
void quat_to_axis_angle(float axis[3], float *angle, const float q[4]);
-void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
void angle_to_mat2(float R[2][2], const float angle);
+void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
+void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle);
void axis_angle_to_quat_single(float q[4], const char axis, const float angle);
@@ -217,8 +218,12 @@ float angle_wrap_deg(float angle);
float angle_compat_rad(float angle, float angle_compat);
-int mat3_from_axis_conversion(int from_forward, int from_up, int to_forward, int to_up,
- float r_mat[3][3]);
+bool mat3_from_axis_conversion(
+ int src_forward, int src_up, int dst_forward, int dst_up,
+ float r_mat[3][3]);
+bool mat3_from_axis_conversion_single(
+ int src_axis, int dst_axis,
+ float r_mat[3][3]);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index d15fe1a95dc..4fdb33926a2 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -234,6 +234,7 @@ void mid_v3_v3v3(float r[3], const float a[3], const float b[3]);
void mid_v2_v2v2(float r[2], const float a[2], const float b[2]);
void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3]);
void mid_v3_v3v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
+void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr);
void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3]);
void mid_v3_angle_weighted(float r[3]);
@@ -285,6 +286,8 @@ float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT;
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT;
float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2]) ATTR_WARN_UNUSED_RESULT;
+float angle_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
+float angle_signed_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT;
float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
@@ -296,8 +299,12 @@ void angle_poly_v3(float *angles, const float *verts[3], int len);
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_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2]);
+void project_v3_v3v3_normalized(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_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
+void project_plane_normalized_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]);
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index 1a626ff44bd..b59e7f99d59 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -39,20 +39,12 @@ extern "C" {
struct ListBase;
-#ifdef WIN32
-#define SEP '\\'
-#define ALTSEP '/'
-#else
-#define SEP '/'
-#define ALTSEP '\\'
-#endif
-
void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1);
void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file);
void BLI_make_exist(char *dir);
-void BLI_make_existing_file(const char *name);
+bool BLI_make_existing_file(const char *name);
void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen);
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen);
void BLI_split_file_part(const char *string, char *file, const size_t filelen);
@@ -60,7 +52,13 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen,
const char *__restrict file) ATTR_NONNULL();
void BLI_join_dirfile(char *__restrict string, const size_t maxlen,
const char *__restrict dir, const char *__restrict file) ATTR_NONNULL();
+size_t BLI_path_join(
+ char *__restrict dst, const size_t dst_len,
+ const char *path_first, ...) ATTR_NONNULL(1, 3) ATTR_SENTINEL(0);
const char *BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+bool BLI_path_name_at_index(
+ const char *__restrict path, const int index,
+ int *__restrict r_offset, int *__restrict r_len) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
#if 0
typedef enum bli_rebase_state {
@@ -83,7 +81,6 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen);
#endif
bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name);
-void BLI_getlastdir(const char *dir, char *last, const size_t maxlen);
bool BLI_testextensie(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
bool BLI_testextensie_n(const char *str, ...) ATTR_NONNULL(1) ATTR_SENTINEL(0);
bool BLI_testextensie_array(const char *str, const char **ext_array) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
@@ -91,13 +88,8 @@ bool BLI_testextensie_glob(const char *str, const char *ext_fnmatch) ATTR_NONNUL
bool BLI_replace_extension(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
bool BLI_ensure_extension(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL();
-bool BLI_uniquename(struct ListBase *list, void *vlink, const char *defname, char delim, int name_offs, int len);
-bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name),
- void *arg, const char *defname, char delim, char *name, int name_len);
-void BLI_newname(char *name, int add);
int BLI_stringdec(const char *string, char *head, char *start, unsigned short *numlen);
void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic);
-int BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
/* removes trailing slash */
void BLI_cleanup_file(const char *relabase, char *path) ATTR_NONNULL(2);
@@ -148,6 +140,18 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
# define FILE_MAX 1024
#endif
+#ifdef WIN32
+# define SEP '\\'
+# define ALTSEP '/'
+# define SEP_STR "\\"
+# define ALTSEP_STR "/"
+#else
+# define SEP '/'
+# define ALTSEP '\\'
+# define SEP_STR "/"
+# define ALTSEP_STR "\\"
+#endif
+
/* Parent and current dir helpers. */
#define FILENAME_PARENT ".."
#define FILENAME_CURRENT "."
diff --git a/source/blender/blenlib/BLI_polyfill2d_beautify.h b/source/blender/blenlib/BLI_polyfill2d_beautify.h
index 20e53b080fe..29a900200bb 100644
--- a/source/blender/blenlib/BLI_polyfill2d_beautify.h
+++ b/source/blender/blenlib/BLI_polyfill2d_beautify.h
@@ -33,8 +33,12 @@ void BLI_polyfill_beautify(
/* structs for reuse */
struct MemArena *arena, struct Heap *eheap, struct EdgeHash *eh);
-float BLI_polyfill_beautify_quad_rotate_calc(
- const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
+float BLI_polyfill_beautify_quad_rotate_calc_ex(
+ const float v1[2], const float v2[2], const float v3[2], const float v4[2],
+ const bool lock_degenerate);
+#define BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4) \
+ BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false)
+
/* avoid realloc's when creating new structures for polyfill ngons */
#define BLI_POLYFILL_ALLOC_NGON_RESERVE 64
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index 59bf3644912..471d875c9af 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -47,12 +47,16 @@ bool BLI_rcti_is_empty(const struct rcti *rect);
bool BLI_rctf_is_empty(const struct rctf *rect);
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax);
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax);
+void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size);
+void BLI_rcti_init_pt_radius(struct rcti *rect, const int xy[2], int size);
void BLI_rcti_init_minmax(struct rcti *rect);
void BLI_rctf_init_minmax(struct rctf *rect);
void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2]);
void BLI_rctf_do_minmax_v(struct rctf *rect, const float xy[2]);
void BLI_rctf_transform_pt_v(const rctf *dst, const rctf *src, float xy_dst[2], const float xy_src[2]);
+void BLI_rctf_transform_calc_m4_pivot_min_ex(const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y);
+void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, float matrix[4][4]);
void BLI_rctf_translate(struct rctf *rect, float x, float y);
void BLI_rcti_translate(struct rcti *rect, int x, int y);
@@ -95,6 +99,7 @@ void BLI_rctf_union(struct rctf *rctf1, const struct rctf *rctf2);
void BLI_rcti_rctf_copy(struct rcti *dst, const struct rctf *src);
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src);
void BLI_rcti_rctf_copy_floor(struct rcti *dst, const struct rctf *src);
+void BLI_rcti_rctf_copy_round(struct rcti *dst, const struct rctf *src);
void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle);
diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h
index 222005ee92e..d54f2a7bab2 100644
--- a/source/blender/blenlib/BLI_stack.h
+++ b/source/blender/blenlib/BLI_stack.h
@@ -30,6 +30,10 @@
#include "BLI_compiler_attrs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct BLI_Stack BLI_Stack;
BLI_Stack *BLI_stack_new_ex(
@@ -55,4 +59,8 @@ size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONN
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BLI_STACK_H__ */
diff --git a/source/blender/blenlib/BLI_strict_flags.h b/source/blender/blenlib/BLI_strict_flags.h
index 964ee06469d..86b7285655e 100644
--- a/source/blender/blenlib/BLI_strict_flags.h
+++ b/source/blender/blenlib/BLI_strict_flags.h
@@ -30,6 +30,8 @@
#ifdef __GNUC__
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */
# pragma GCC diagnostic error "-Wsign-compare"
+# endif
+# if __GNUC__ >= 6 /* gcc6+ only */
# pragma GCC diagnostic error "-Wconversion"
# endif
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 408
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index 0740b574c1a..32504a88b48 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -36,8 +36,8 @@ extern "C" {
char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL();
size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL();
char *BLI_strncat_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL();
-int BLI_utf8_invalid_byte(const char *str, int length) ATTR_NONNULL();
-int BLI_utf8_invalid_strip(char *str, int length) ATTR_NONNULL();
+ptrdiff_t BLI_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL();
+int BLI_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL();
int BLI_str_utf8_size(const char *p) ATTR_NONNULL(); /* warning, can return -1 on bad chars */
int BLI_str_utf8_size_safe(const char *p) ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h
new file mode 100644
index 00000000000..5701bce51ea
--- /dev/null
+++ b/source/blender/blenlib/BLI_string_utils.h
@@ -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) 2017 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_STRING_UTILS_H__
+#define __BLI_STRING_UTILS_H__
+
+/** \file BLI_string_utils.h
+ * \ingroup bli
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines_variadic.h"
+
+struct ListBase;
+
+typedef bool (*UniquenameCheckCallback)(void *arg, const char *name);
+
+size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
+
+void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len);
+void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len);
+
+/* Join strings, return newly allocated string. */
+char *BLI_string_join_arrayN(
+ const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+char *BLI_string_join_array_by_sep_charN(
+ char sep, const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+char *BLI_string_join_array_by_sep_char_with_tableN(
+ char sep, char *table[], const char *strings[], uint strings_len) ATTR_NONNULL();
+/* Take multiple arguments, pass as (array, length). */
+#define BLI_string_joinN(...) \
+ BLI_string_join_arrayN( \
+ ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+#define BLI_string_join_by_sep_charN(sep, ...) \
+ BLI_string_join_array_by_sep_charN( \
+ sep, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+#define BLI_string_join_by_sep_char_with_tableN(sep, table, ...) \
+ BLI_string_join_array_by_sep_char_with_tableN( \
+ sep, table, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+
+void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len);
+
+bool BLI_uniquename_cb(
+ UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len);
+bool BLI_uniquename(
+ struct ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_STRING_UTILS_H__ */
diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h
index 7929e1d6551..9477f61713c 100644
--- a/source/blender/blenlib/BLI_sys_types.h
+++ b/source/blender/blenlib/BLI_sys_types.h
@@ -65,8 +65,8 @@ typedef uint64_t u_int64_t;
#include <inttypes.h>
-/* MinGW and MSVC >= 2010 */
-#elif defined(FREE_WINDOWS) || defined(_MSC_VER)
+/* MSVC >= 2010 */
+#elif defined(_MSC_VER)
#include <stdint.h>
#else
@@ -80,6 +80,11 @@ typedef uint64_t u_int64_t;
#include <stddef.h> /* size_t define */
#include <stdbool.h>
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+typedef unsigned char uchar;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 967e0be6d0a..721327d26a8 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -81,6 +81,7 @@ typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata, int
TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata);
TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void *userdata);
+TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler, void *userdata);
void BLI_task_pool_free(TaskPool *pool);
void BLI_task_pool_push_ex(
@@ -95,14 +96,6 @@ void BLI_task_pool_push_from_thread(TaskPool *pool, TaskRunFunction run,
void BLI_task_pool_work_and_wait(TaskPool *pool);
/* cancel all tasks, keep worker threads running */
void BLI_task_pool_cancel(TaskPool *pool);
-/* stop all worker threads */
-void BLI_task_pool_stop(TaskPool *pool);
-
-/* get number of threads allowed to be used by this pool */
-int BLI_pool_get_num_threads(TaskPool *pool);
-
-/* set number of threads allowed to be used by this pool */
-void BLI_pool_set_num_threads(TaskPool *pool, int num_threads);
/* for worker threads, test if canceled */
bool BLI_task_pool_canceled(TaskPool *pool);
@@ -113,8 +106,12 @@ void *BLI_task_pool_userdata(TaskPool *pool);
/* optional mutex to use from run function */
ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool);
-/* number of tasks done, for stats, don't use this to make decisions */
-size_t BLI_task_pool_tasks_done(TaskPool *pool);
+/* Delayed push, use that to reduce thread overhead by accumulating
+ * all new tasks into local queue first and pushing it to scheduler
+ * from within a single mutex lock.
+ */
+void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id);
+void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id);
/* Parallel for routines */
typedef void (*TaskParallelRangeFunc)(void *userdata, const int iter);
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 746eb922c65..66c7f247f61 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -39,35 +39,12 @@ extern "C" {
/* avoid many includes for now */
#include "BLI_sys_types.h"
#include "BLI_compiler_compat.h"
+#include "BLI_utildefines_variadic.h"
#ifndef NDEBUG /* for BLI_assert */
#include <stdio.h>
#endif
-
-/* varargs macros (keep first so others can use) */
-/* --- internal helpers --- */
-#define _VA_NARGS_GLUE(x, y) x y
-#define _VA_NARGS_RETURN_COUNT(\
- _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \
- _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \
- _33_, _34_, _35_, _36_, _37_, _38_, _39_, _40_, _41_, _42_, _43_, _44_, _45_, _46_, _47_, _48_, \
- _49_, _50_, _51_, _52_, _53_, _54_, _55_, _56_, _57_, _58_, _59_, _60_, _61_, _62_, _63_, _64_, \
- count, ...) count
-#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args
-/* 64 args max */
-#define _VA_NARGS_COUNT(...) _VA_NARGS_EXPAND((__VA_ARGS__, \
- 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \
- 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \
- 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
- 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
-#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count
-#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count)
-#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count)
-/* --- expose for re-use --- */
-#define VA_NARGS_CALL_OVERLOAD(name, ...) \
- _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, _VA_NARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__))
-
/* useful for finding bad use of min/max */
#if 0
/* gcc only */
diff --git a/source/blender/blenlib/BLI_utildefines_iter.h b/source/blender/blenlib/BLI_utildefines_iter.h
new file mode 100644
index 00000000000..094c1a4b3dc
--- /dev/null
+++ b/source/blender/blenlib/BLI_utildefines_iter.h
@@ -0,0 +1,52 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_UTILDEFINES_ITER_H__
+#define __BLI_UTILDEFINES_ITER_H__
+
+/** \file BLI_utildefines_iter.h
+ * \ingroup bli
+ *
+ * General looping helpers, use `BLI_FOREACH` prefix.
+ */
+
+/**
+ * Even value distribution.
+ *
+ * \a src must be larger than \a dst,
+ * \a dst defines the number of iterations, their values are evenly spaced.
+ *
+ * The following pairs represent (src, dst) arguments and the values they loop over.
+ * <pre>
+ * (19, 4) -> [2, 7, 11. 16]
+ * (100, 5) -> [9, 29, 49, 69, 89]
+ * (100, 3) -> [16, 49, 83]
+ * (100, 100) -> [0..99]
+ * </pre>
+ * \note this is mainly useful for numbers that might not divide evenly into eachother.
+ */
+#define BLI_FOREACH_SPARSE_RANGE(src, dst, i) \
+for (int _src = (src), _src2 = _src * 2, _dst2 = (dst) * 2, _error = _dst2 - _src, i = 0, _delta; \
+ ((void)(_delta = divide_floor_i(_error, _dst2)), \
+ (void)(i -= _delta), \
+ (i < _src)); \
+ _error -= (_delta * _dst2) + _src2)
+
+#endif /* __BLI_UTILDEFINES_ITER_H__ */
diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_utildefines_stack.h
index 42b11eb9a2b..15b0029e727 100644
--- a/source/blender/blenlib/BLI_stackdefines.h
+++ b/source/blender/blenlib/BLI_utildefines_stack.h
@@ -18,10 +18,10 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#ifndef __BLI_STACKDEFINES_H__
-#define __BLI_STACKDEFINES_H__
+#ifndef __BLI_UTILDEFINES_STACK_H__
+#define __BLI_UTILDEFINES_STACK_H__
-/** \file BLI_stackdefines.h
+/** \file BLI_utildefines_stack.h
* \ingroup bli
*
* Macro's for a simple array based stack
@@ -86,4 +86,4 @@
} ((void)0)
#endif
-#endif /* __BLI_STACKDEFINES_H__ */
+#endif /* __BLI_UTILDEFINES_STACK_H__ */
diff --git a/source/blender/blenlib/BLI_utildefines_variadic.h b/source/blender/blenlib/BLI_utildefines_variadic.h
new file mode 100644
index 00000000000..7c15754fd83
--- /dev/null
+++ b/source/blender/blenlib/BLI_utildefines_variadic.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_UTILDEFINES_VARIADIC_H__
+#define __BLI_UTILDEFINES_VARIADIC_H__
+
+/** \file BLI_utildefines_variadic.h
+ * \ingroup bli
+ */
+
+/* --- internal helpers --- */
+#define _VA_NARGS_GLUE(x, y) x y
+#define _VA_NARGS_RETURN_COUNT(\
+ _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \
+ _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \
+ _33_, _34_, _35_, _36_, _37_, _38_, _39_, _40_, _41_, _42_, _43_, _44_, _45_, _46_, _47_, _48_, \
+ _49_, _50_, _51_, _52_, _53_, _54_, _55_, _56_, _57_, _58_, _59_, _60_, _61_, _62_, _63_, _64_, \
+ count, ...) count
+#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args
+#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count
+#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count)
+#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count)
+/* --- expose for re-use --- */
+/* 64 args max */
+#define VA_NARGS_COUNT(...) _VA_NARGS_EXPAND((__VA_ARGS__, \
+ 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \
+ 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
+ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
+#define VA_NARGS_CALL_OVERLOAD(name, ...) \
+ _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, VA_NARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__))
+
+#endif /* __BLI_UTILDEFINES_VARIADIC_H__ */
diff --git a/source/blender/blenlib/BLI_vfontdata.h b/source/blender/blenlib/BLI_vfontdata.h
index 8a7079b6c5f..0cd50319a33 100644
--- a/source/blender/blenlib/BLI_vfontdata.h
+++ b/source/blender/blenlib/BLI_vfontdata.h
@@ -52,8 +52,10 @@ typedef struct VChar {
} VChar;
VFontData *BLI_vfontdata_from_freetypefont(struct PackedFile *pf);
+VFontData *BLI_vfontdata_copy(const VFontData *vfont_src, const int flag);
VChar *BLI_vfontchar_from_freetypefont(struct VFont *vfont, unsigned long character);
+VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int flag);
#endif
diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h
index b421b7dbb90..6fbbed01400 100644
--- a/source/blender/blenlib/BLI_winstuff.h
+++ b/source/blender/blenlib/BLI_winstuff.h
@@ -37,15 +37,6 @@
# error "This include is for Windows only!"
#endif
-#ifdef FREE_WINDOWS
-# ifdef WINVER
-# undef WINVER
-# endif
-
-/* Some stuff requires WINVER 0x500, but mingw's default is 0x400 */
-# define WINVER 0x0501
-#endif
-
#define WIN32_LEAN_AND_MEAN
#ifndef WIN32_SKIP_HKEY_PROTECTION
@@ -94,7 +85,7 @@ extern "C" {
# define snprintf _snprintf
#endif
-#if defined(_MSC_VER) || (defined(FREE_WINDOWS) && !defined(FREE_WINDOWS64))
+#if defined(_MSC_VER)
# define R_OK 4
# define W_OK 2
// not accepted by access() on windows
@@ -102,28 +93,22 @@ extern "C" {
# define F_OK 0
#endif
-#ifndef FREE_WINDOWS
typedef unsigned int mode_t;
-#endif
/* use functions that take a 64 bit offset for files larger than 4GB */
-#ifndef FREE_WINDOWS
-# include <stdio.h>
-# define fseek(stream, offset, origin) _fseeki64(stream, offset, origin)
-# define ftell(stream) _ftelli64(stream)
-# define lseek(fd, offset, origin) _lseeki64(fd, offset, origin)
-# define tell(fd) _telli64(fd)
-#endif
+#include <stdio.h>
+#define fseek(stream, offset, origin) _fseeki64(stream, offset, origin)
+#define ftell(stream) _ftelli64(stream)
+#define lseek(fd, offset, origin) _lseeki64(fd, offset, origin)
+#define tell(fd) _telli64(fd)
+
-/* mingw using _SSIZE_T_ to declare ssize_t type */
#ifndef _SSIZE_T_
# define _SSIZE_T_
/* python uses HAVE_SSIZE_T */
# ifndef HAVE_SSIZE_T
# define HAVE_SSIZE_T 1
-# ifndef FREE_WINDOWS64
typedef long ssize_t;
-# endif
# endif
#endif
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 6e717a3ae7e..61a1241cd8f 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -109,6 +109,7 @@ set(SRC
intern/string.c
intern/string_cursor_utf8.c
intern/string_utf8.c
+ intern/string_utils.c
intern/system.c
intern/task.c
intern/threads.c
@@ -151,6 +152,7 @@ set(SRC
BLI_ghash.h
BLI_graph.h
BLI_gsqueue.h
+ BLI_hash.h
BLI_hash_md5.h
BLI_hash_mm2a.h
BLI_heap.h
@@ -190,17 +192,20 @@ set(SRC
BLI_sort.h
BLI_sort_utils.h
BLI_stack.h
- BLI_stackdefines.h
BLI_strict_flags.h
BLI_string.h
BLI_string_cursor_utf8.h
BLI_string_utf8.h
+ BLI_string_utils.h
BLI_sys_types.h
BLI_system.h
BLI_task.h
BLI_threads.h
BLI_timecode.h
BLI_utildefines.h
+ BLI_utildefines_iter.h
+ BLI_utildefines_stack.h
+ BLI_utildefines_variadic.h
BLI_uvproject.h
BLI_vfontdata.h
BLI_voronoi.h
diff --git a/source/blender/blenlib/PIL_time_utildefines.h b/source/blender/blenlib/PIL_time_utildefines.h
index 9157e04a7bf..412cfb3a090 100644
--- a/source/blender/blenlib/PIL_time_utildefines.h
+++ b/source/blender/blenlib/PIL_time_utildefines.h
@@ -80,9 +80,10 @@
} \
const float _delta_##var = TIMEIT_VALUE(var); \
_sum_##var += _delta_##var; \
+ _num_##var++; \
printf("time end (" #var "): %.6f" " " AT "\n", _delta_##var); \
- printf("time averaged (" #var "): %.6f" " " AT "\n", \
- (_sum_##var / ++_num_##var)); \
+ printf("time averaged (" #var "): %.6f (total: %.6f, in %d runs)\n", \
+ (_sum_##var / _num_##var), _sum_##var, (int)_num_##var); \
fflush(stdout); \
} (void)0
diff --git a/source/blender/blenlib/intern/BLI_dial.c b/source/blender/blenlib/intern/BLI_dial.c
index cfbb52847fd..89f18fa10b4 100644
--- a/source/blender/blenlib/intern/BLI_dial.c
+++ b/source/blender/blenlib/intern/BLI_dial.c
@@ -46,7 +46,7 @@ struct Dial {
};
-Dial *BLI_dial_initialize(float start_position[2], float threshold)
+Dial *BLI_dial_initialize(const float start_position[2], float threshold)
{
Dial *dial = MEM_callocN(sizeof(Dial), "dial");
@@ -56,7 +56,7 @@ Dial *BLI_dial_initialize(float start_position[2], float threshold)
return dial;
}
-float BLI_dial_angle(Dial *dial, float current_position[2])
+float BLI_dial_angle(Dial *dial, const float current_position[2])
{
float current_direction[2];
diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c
index ecd4a6e6b09..bce6614beb5 100644
--- a/source/blender/blenlib/intern/BLI_dynstr.c
+++ b/source/blender/blenlib/intern/BLI_dynstr.c
@@ -35,6 +35,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_memarena.h"
#include "BLI_string.h"
#include "BLI_dynstr.h"
@@ -64,6 +65,7 @@ struct DynStrElem {
struct DynStr {
DynStrElem *elems, *last;
int curlen;
+ MemArena *memarena;
};
/***/
@@ -78,11 +80,32 @@ DynStr *BLI_dynstr_new(void)
DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
ds->elems = ds->last = NULL;
ds->curlen = 0;
+ ds->memarena = NULL;
return ds;
}
/**
+ * Create a new DynStr.
+ *
+ * \return Pointer to a new DynStr.
+ */
+DynStr *BLI_dynstr_new_memarena(void)
+{
+ DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
+ ds->elems = ds->last = NULL;
+ ds->curlen = 0;
+ ds->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ return ds;
+}
+
+BLI_INLINE void *dynstr_alloc(DynStr *__restrict ds, size_t size)
+{
+ return ds->memarena ? BLI_memarena_alloc(ds->memarena, size) : malloc(size);
+}
+
+/**
* Append a c-string to a DynStr.
*
* \param ds The DynStr to append to.
@@ -90,10 +113,10 @@ DynStr *BLI_dynstr_new(void)
*/
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
{
- DynStrElem *dse = malloc(sizeof(*dse));
+ DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
int cstrlen = strlen(cstr);
- dse->str = malloc(cstrlen + 1);
+ dse->str = dynstr_alloc(ds, cstrlen + 1);
memcpy(dse->str, cstr, cstrlen + 1);
dse->next = NULL;
@@ -114,10 +137,10 @@ void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
*/
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len)
{
- DynStrElem *dse = malloc(sizeof(*dse));
+ DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
int cstrlen = BLI_strnlen(cstr, len);
- dse->str = malloc(cstrlen + 1);
+ dse->str = dynstr_alloc(ds, cstrlen + 1);
memcpy(dse->str, cstr, cstrlen);
dse->str[cstrlen] = '\0';
dse->next = NULL;
@@ -296,22 +319,41 @@ char *BLI_dynstr_get_cstring(DynStr *ds)
}
/**
+ * Clear the DynStr
+ *
+ * \param ds The DynStr to clear.
+ */
+void BLI_dynstr_clear(DynStr *ds)
+{
+ if (ds->memarena) {
+ BLI_memarena_clear(ds->memarena);
+ }
+ else {
+ for (DynStrElem *dse_next, *dse = ds->elems; dse; dse = dse_next) {
+ dse_next = dse->next;
+
+ free(dse->str);
+ free(dse);
+ }
+ }
+
+ ds->elems = ds->last = NULL;
+ ds->curlen = 0;
+}
+
+/**
* Free the DynStr
*
* \param ds The DynStr to free.
*/
void BLI_dynstr_free(DynStr *ds)
{
- DynStrElem *dse;
-
- for (dse = ds->elems; dse; ) {
- DynStrElem *n = dse->next;
-
- free(dse->str);
- free(dse);
-
- dse = n;
+ if (ds->memarena) {
+ BLI_memarena_free(ds->memarena);
}
-
+ else {
+ BLI_dynstr_clear(ds);
+ }
+
MEM_freeN(ds);
}
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 944ee18e6b2..1b2a27e33d8 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -116,6 +116,12 @@ struct GHash {
};
+/* -------------------------------------------------------------------- */
+/* GHash API */
+
+/** \name Internal Utility API
+ * \{ */
+
BLI_INLINE void ghash_entry_copy(
GHash *gh_dst, Entry *dst, GHash *gh_src, Entry *src,
GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
@@ -132,12 +138,6 @@ BLI_INLINE void ghash_entry_copy(
}
}
-/* -------------------------------------------------------------------- */
-/* GHash API */
-
-/** \name Internal Utility API
- * \{ */
-
/**
* Get the full hash for a key.
*/
@@ -763,6 +763,28 @@ bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreef
}
/**
+ * Replaces the key of an item in the \a gh.
+ *
+ * Use when a key is re-allocated or it's memory location is changed.
+ *
+ * \returns The previous key or NULL if not found, the caller may free if it's needed.
+ */
+void *BLI_ghash_replace_key(GHash *gh, void *key)
+{
+ const unsigned int hash = ghash_keyhash(gh, key);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index);
+ if (e != NULL) {
+ void *key_prev = e->e.key;
+ e->e.key = key;
+ return key_prev;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/**
* Lookup the value of \a key in \a gh.
*
* \param key The key to lookup.
@@ -1225,6 +1247,11 @@ bool BLI_ghashutil_intcmp(const void *a, const void *b)
return (a != b);
}
+size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b)
+{
+ return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
+}
+
/**
* This function implements the widely used "djb" hash apparently posted
* by Daniel Bernstein to comp.lang.c some time ago. The 32 bit
@@ -1429,6 +1456,18 @@ bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
return ghash_insert_safe_keyonly((GHash *)gs, key, true, keyfreefp);
}
+/**
+ * Replaces the key to the set if it's found.
+ * Matching #BLI_ghash_replace_key
+ *
+ * \returns The old key or NULL if not found.
+ */
+void *BLI_gset_replace_key(GSet *gs, void *key)
+{
+ return BLI_ghash_replace_key((GHash *)gs, key);
+}
+
+
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
{
return BLI_ghash_remove((GHash *)gs, key, keyfreefp, NULL);
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index b14007a88cb..e5ca53a0193 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -55,12 +55,20 @@
#include "BLI_stack.h"
#include "BLI_kdopbvh.h"
#include "BLI_math.h"
-#include "BLI_strict_flags.h"
#include "BLI_task.h"
+#include "BLI_strict_flags.h"
+
/* used for iterative_raycast */
// #define USE_SKIP_LINKS
+/* Use to print balanced output. */
+// #define USE_PRINT_TREE
+
+/* Check tree is valid. */
+// #define USE_VERIFY_TREE
+
+
#define MAX_TREETYPE 32
/* Setting zero so we can catch bugs in BLI_task/KDOPBVH.
@@ -129,7 +137,7 @@ typedef struct BVHOverlapData_Thread {
} BVHOverlapData_Thread;
typedef struct BVHNearestData {
- BVHTree *tree;
+ const BVHTree *tree;
const float *co;
BVHTree_NearestPointCallback callback;
void *userdata;
@@ -139,7 +147,7 @@ typedef struct BVHNearestData {
} BVHNearestData;
typedef struct BVHRayCastData {
- BVHTree *tree;
+ const BVHTree *tree;
BVHTree_RayCastCallback callback;
void *userdata;
@@ -159,29 +167,6 @@ typedef struct BVHRayCastData {
BVHTreeRayHit hit;
} BVHRayCastData;
-typedef struct BVHNearestRayData {
- BVHTree *tree;
- BVHTree_NearestToRayCallback callback;
- void *userdata;
-
- 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;
-
/** \} */
@@ -194,9 +179,9 @@ typedef struct BVHNearestRayData {
*/
const float bvhtree_kdop_axes[13][3] = {
- {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0}, {1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, -1.0},
- {1.0, -1.0, -1.0}, {1.0, 1.0, 0}, {1.0, 0, 1.0}, {0, 1.0, 1.0}, {1.0, -1.0, 0}, {1.0, 0, -1.0},
- {0, 1.0, -1.0}
+ {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0},
+ {1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, -1.0}, {1.0, -1.0, -1.0},
+ {1.0, 1.0, 0}, {1.0, 0, 1.0}, {0, 1.0, 1.0}, {1.0, -1.0, 0}, {1.0, 0, -1.0}, {0, 1.0, -1.0}
};
@@ -344,11 +329,16 @@ static int bvh_partition(BVHNode **a, int lo, int hi, BVHNode *x, int axis)
{
int i = lo, j = hi;
while (1) {
- while ((a[i])->bv[axis] < x->bv[axis]) i++;
+ while (a[i]->bv[axis] < x->bv[axis]) {
+ i++;
+ }
j--;
- while (x->bv[axis] < (a[j])->bv[axis]) j--;
- if (!(i < j))
+ while (x->bv[axis] < a[j]->bv[axis]) {
+ j--;
+ }
+ if (!(i < j)) {
return i;
+ }
SWAP(BVHNode *, a[i], a[j]);
i++;
}
@@ -450,19 +440,18 @@ static void sort_along_axis(BVHTree *tree, int start, int end, int axis)
* \note after a call to this function you can expect one of:
* - every node to left of a[n] are smaller or equal to it
* - every node to the right of a[n] are greater or equal to it */
-static int partition_nth_element(BVHNode **a, int _begin, int _end, int n, int axis)
+static void partition_nth_element(BVHNode **a, int begin, int end, const int n, const int axis)
{
- int begin = _begin, end = _end, cut;
while (end - begin > 3) {
- cut = bvh_partition(a, begin, end, bvh_medianof3(a, begin, (begin + end) / 2, end - 1, axis), axis);
- if (cut <= n)
+ const int cut = bvh_partition(a, begin, end, bvh_medianof3(a, begin, (begin + end) / 2, end - 1, axis), axis);
+ if (cut <= n) {
begin = cut;
- else
+ }
+ else {
end = cut;
+ }
}
bvh_insertionsort(a, begin, end, axis);
-
- return n;
}
#ifdef USE_SKIP_LINKS
@@ -487,7 +476,7 @@ static void build_skip_links(BVHTree *tree, BVHNode *node, BVHNode *left, BVHNod
/*
* BVHTree bounding volumes functions
*/
-static void create_kdop_hull(BVHTree *tree, BVHNode *node, const float *co, int numpoints, int moving)
+static void create_kdop_hull(const BVHTree *tree, BVHNode *node, const float *co, int numpoints, int moving)
{
float newminmax;
float *bv = node->bv;
@@ -514,7 +503,7 @@ static void create_kdop_hull(BVHTree *tree, BVHNode *node, const float *co, int
/**
* \note depends on the fact that the BVH's for each face is already build
*/
-static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end)
+static void refit_kdop_hull(const BVHTree *tree, BVHNode *node, int start, int end)
{
float newmin, newmax;
float *bv = node->bv;
@@ -589,10 +578,12 @@ static void node_join(BVHTree *tree, BVHNode *node)
}
}
-/*
+#ifdef USE_PRINT_TREE
+
+/**
* Debug and information functions
*/
-#if 0
+
static void bvhtree_print_tree(BVHTree *tree, BVHNode *node, int depth)
{
int i;
@@ -615,26 +606,29 @@ static void bvhtree_print_tree(BVHTree *tree, BVHNode *node, int depth)
static void bvhtree_info(BVHTree *tree)
{
- printf("BVHTree info\n");
- printf("tree_type = %d, axis = %d, epsilon = %f\n", tree->tree_type, tree->axis, tree->epsilon);
- printf("nodes = %d, branches = %d, leafs = %d\n", tree->totbranch + tree->totleaf, tree->totbranch, tree->totleaf);
- printf("Memory per node = %ldbytes\n", sizeof(BVHNode) + sizeof(BVHNode *) * tree->tree_type + sizeof(float) * tree->axis);
- printf("BV memory = %dbytes\n", (int)MEM_allocN_len(tree->nodebv));
-
- printf("Total memory = %ldbytes\n", sizeof(BVHTree) +
- MEM_allocN_len(tree->nodes) +
- MEM_allocN_len(tree->nodearray) +
- MEM_allocN_len(tree->nodechild) +
- MEM_allocN_len(tree->nodebv));
-
-// bvhtree_print_tree(tree, tree->nodes[tree->totleaf], 0);
-}
-#endif
+ printf("BVHTree Info: tree_type = %d, axis = %d, epsilon = %f\n",
+ tree->tree_type, tree->axis, tree->epsilon);
+ printf("nodes = %d, branches = %d, leafs = %d\n",
+ tree->totbranch + tree->totleaf, tree->totbranch, tree->totleaf);
+ printf("Memory per node = %ubytes\n",
+ (uint)(sizeof(BVHNode) + sizeof(BVHNode *) * tree->tree_type + sizeof(float) * tree->axis));
+ printf("BV memory = %ubytes\n",
+ (uint)MEM_allocN_len(tree->nodebv));
-#if 0
+ printf("Total memory = %ubytes\n",
+ (uint)(sizeof(BVHTree) +
+ MEM_allocN_len(tree->nodes) +
+ MEM_allocN_len(tree->nodearray) +
+ MEM_allocN_len(tree->nodechild) +
+ MEM_allocN_len(tree->nodebv)));
+ bvhtree_print_tree(tree, tree->nodes[tree->totleaf], 0);
+}
+#endif /* USE_PRINT_TREE */
+
+#ifdef USE_VERIFY_TREE
-static void verify_tree(BVHTree *tree)
+static void bvhtree_verify(BVHTree *tree)
{
int i, j, check = 0;
@@ -672,12 +666,14 @@ static void verify_tree(BVHTree *tree)
}
}
- printf("branches: %d, leafs: %d, total: %d\n", tree->totbranch, tree->totleaf, tree->totbranch + tree->totleaf);
+ printf("branches: %d, leafs: %d, total: %d\n",
+ tree->totbranch, tree->totleaf, tree->totbranch + tree->totleaf);
}
-#endif
+#endif /* USE_VERIFY_TREE */
/* Helper data and structures to build a min-leaf generalized implicit tree
- * This code can be easily reduced (basicly this is only method to calculate pow(k, n) in O(1).. and stuff like that) */
+ * This code can be easily reduced
+ * (basicly this is only method to calculate pow(k, n) in O(1).. and stuff like that) */
typedef struct BVHBuildHelper {
int tree_type; /* */
int totleafs; /* */
@@ -689,7 +685,7 @@ typedef struct BVHBuildHelper {
} BVHBuildHelper;
-static void build_implicit_tree_helper(BVHTree *tree, BVHBuildHelper *data)
+static void build_implicit_tree_helper(const BVHTree *tree, BVHBuildHelper *data)
{
int depth = 0;
int remain;
@@ -719,7 +715,7 @@ static void build_implicit_tree_helper(BVHTree *tree, BVHBuildHelper *data)
}
// return the min index of all the leafs archivable with the given branch
-static int implicit_leafs_index(BVHBuildHelper *data, int depth, int child_index)
+static int implicit_leafs_index(const BVHBuildHelper *data, const int depth, const int child_index)
{
int min_leaf_index = child_index * data->leafs_per_child[depth - 1];
if (min_leaf_index <= data->remain_leafs)
@@ -734,8 +730,8 @@ static int implicit_leafs_index(BVHBuildHelper *data, int depth, int child_index
* Generalized implicit tree build
*
* An implicit tree is a tree where its structure is implied, thus there is no need to store child pointers or indexs.
- * Its possible to find the position of the child or the parent with simple maths (multiplication and adittion). This type
- * of tree is for example used on heaps.. where node N has its childs at indexs N*2 and N*2+1.
+ * Its possible to find the position of the child or the parent with simple maths (multiplication and adittion).
+ * This type of tree is for example used on heaps.. where node N has its childs at indexs N*2 and N*2+1.
*
* Although in this case the tree type is general.. and not know until runtime.
* tree_type stands for the maximum number of childs that a tree node can have.
@@ -776,7 +772,7 @@ static int implicit_needed_branches(int tree_type, int leafs)
*
* TODO: This can be optimized a bit by doing a specialized nth_element instead of K nth_elements
*/
-static void split_leafs(BVHNode **leafs_array, int *nth, int partitions, int split_axis)
+static void split_leafs(BVHNode **leafs_array, const int nth[], const int partitions, const int split_axis)
{
int i;
for (i = 0; i < partitions - 1; i++) {
@@ -788,14 +784,14 @@ static void split_leafs(BVHNode **leafs_array, int *nth, int partitions, int spl
}
typedef struct BVHDivNodesData {
- BVHTree *tree;
+ const BVHTree *tree;
BVHNode *branches_array;
BVHNode **leafs_array;
int tree_type;
int tree_offset;
- BVHBuildHelper *data;
+ const BVHBuildHelper *data;
int depth;
int i;
@@ -808,7 +804,7 @@ static void non_recursive_bvh_div_nodes_task_cb(void *userdata, const int j)
int k;
const int parent_level_index = j - data->i;
- BVHNode *parent = data->branches_array + j;
+ BVHNode *parent = &data->branches_array[j];
int nth_positions[MAX_TREETYPE + 1];
char split_axis;
@@ -847,7 +843,7 @@ static void non_recursive_bvh_div_nodes_task_cb(void *userdata, const int j)
const int child_leafs_end = implicit_leafs_index(data->data, data->depth + 1, child_level_index + 1);
if (child_leafs_end - child_leafs_begin > 1) {
- parent->children[k] = data->branches_array + child_index;
+ parent->children[k] = &data->branches_array[child_index];
parent->children[k]->parent = parent;
}
else if (child_leafs_end - child_leafs_begin == 1) {
@@ -878,7 +874,8 @@ static void non_recursive_bvh_div_nodes_task_cb(void *userdata, const int j)
* To archive this is necessary to find how much leafs are accessible from a certain branch, BVHBuildHelper
* implicit_needed_branches and implicit_leafs_index are auxiliary functions to solve that "optimal-split".
*/
-static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array, BVHNode **leafs_array, int num_leafs)
+static void non_recursive_bvh_div_nodes(
+ const BVHTree *tree, BVHNode *branches_array, BVHNode **leafs_array, int num_leafs)
{
int i;
@@ -890,13 +887,13 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array,
int depth;
/* set parent from root node to NULL */
- BVHNode *tmp = branches_array + 0;
+ BVHNode *tmp = &branches_array[0];
tmp->parent = NULL;
/* Most of bvhtree code relies on 1-leaf trees having at least one branch
* We handle that special case here */
if (num_leafs == 1) {
- BVHNode *root = branches_array + 0;
+ BVHNode *root = &branches_array[0];
refit_kdop_hull(tree, root, 0, num_leafs);
root->main_axis = get_largest_axis(root->bv) / 2;
root->totnode = 1;
@@ -918,16 +915,24 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array,
/* Loop tree levels (log N) loops */
for (i = 1, depth = 1; i <= num_branches; i = i * tree_type + tree_offset, depth++) {
const int first_of_next_level = i * tree_type + tree_offset;
- const int end_j = min_ii(first_of_next_level, num_branches + 1); /* index of last branch on this level */
+ const int i_stop = min_ii(first_of_next_level, num_branches + 1); /* index of last branch on this level */
/* Loop all branches on this level */
cb_data.first_of_next_level = first_of_next_level;
cb_data.i = i;
cb_data.depth = depth;
- BLI_task_parallel_range(
- i, end_j, &cb_data, non_recursive_bvh_div_nodes_task_cb,
- num_leafs > KDOPBVH_THREAD_LEAF_THRESHOLD);
+ if (true) {
+ BLI_task_parallel_range(
+ i, i_stop, &cb_data, non_recursive_bvh_div_nodes_task_cb,
+ num_leafs > KDOPBVH_THREAD_LEAF_THRESHOLD);
+ }
+ else {
+ /* Less hassle for debugging. */
+ for (int i_task = i; i_task < i_stop; i_task++) {
+ non_recursive_bvh_div_nodes_task_cb(&cb_data, i_task);
+ }
+ }
}
}
@@ -1044,7 +1049,8 @@ void BLI_bvhtree_balance(BVHTree *tree)
BVHNode *branches_array = tree->nodearray + tree->totleaf;
BVHNode **leafs_array = tree->nodes;
- /* This function should only be called once (some big bug goes here if its being called more than once per tree) */
+ /* This function should only be called once
+ * (some big bug goes here if its being called more than once per tree) */
BLI_assert(tree->totbranch == 0);
/* Build the implicit tree */
@@ -1060,7 +1066,13 @@ void BLI_bvhtree_balance(BVHTree *tree)
build_skip_links(tree, tree->nodes[tree->totleaf], NULL, NULL);
#endif
- /* bvhtree_info(tree); */
+#ifdef USE_VERIFY_TREE
+ bvhtree_verify(tree);
+#endif
+
+#ifdef USE_PRINT_TREE
+ bvhtree_info(tree);
+#endif
}
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
@@ -1493,7 +1505,8 @@ static void bfs_find_nearest(BVHNearestData *data, BVHNode *node)
else {
/* adjust heap size */
if ((heap_size >= max_heap_size) &&
- ADJUST_MEMORY(default_heap, (void **)&heap, heap_size + 1, &max_heap_size, sizeof(heap[0])) == false)
+ ADJUST_MEMORY(default_heap, (void **)&heap,
+ heap_size + 1, &max_heap_size, sizeof(heap[0])) == false)
{
printf("WARNING: bvh_find_nearest got out of memory\n");
@@ -1900,453 +1913,6 @@ void BLI_bvhtree_ray_cast_all(
/* -------------------------------------------------------------------- */
-/** \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)
-{
- return dist_squared_ray_to_aabb_scaled_v3__impl(
- data, node->bv, NULL,
- data->pick_smallest);
-}
-
-static void dfs_find_lowest_tangent_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_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 {
- 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) {
- 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) {
- dfs_find_nearest_to_ray_dfs(data, node->children[i]);
- }
- }
- }
- }
-}
-
-/**
- * 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;
- BVHNode *root = tree->nodes[tree->totleaf];
-
- data.tree = tree;
-
- data.callback = callback;
- data.userdata = userdata;
-
- 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_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_dist_sq_to_ray(&data, root) < data.nearest.dist_sq) {
- dfs_find_nearest_to_ray_dfs(&data, root);
- }
- }
-
- /* copy back results */
- if (nearest) {
- memcpy(nearest, &data.nearest, sizeof(*nearest));
- }
-
- return data.nearest.index;
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
/** \name BLI_bvhtree_range_query
*
* Allocs and fills an array with the indexs of node that are on the given spherical range (center, radius).
diff --git a/source/blender/blenlib/intern/BLI_kdtree.c b/source/blender/blenlib/intern/BLI_kdtree.c
index a81f9b28b83..84ac339cc4d 100644
--- a/source/blender/blenlib/intern/BLI_kdtree.c
+++ b/source/blender/blenlib/intern/BLI_kdtree.c
@@ -674,3 +674,123 @@ finally:
if (stack != defaultstack)
MEM_freeN(stack);
}
+
+/**
+ * Use when we want to loop over nodes ordered by index.
+ * Requires indices to be aligned with nodes.
+ */
+static uint *kdtree_order(const KDTree *tree)
+{
+ const KDTreeNode *nodes = tree->nodes;
+ uint *order = MEM_mallocN(sizeof(uint) * tree->totnode, __func__);
+ for (uint i = 0; i < tree->totnode; i++) {
+ order[nodes[i].index] = i;
+ }
+ return order;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name BLI_kdtree_calc_duplicates_fast
+ * \{ */
+
+struct DeDuplicateParams {
+ /* Static */
+ const KDTreeNode *nodes;
+ float range;
+ float range_sq;
+ int *duplicates;
+ int *duplicates_found;
+
+ /* Per Search */
+ float search_co[3];
+ int search;
+};
+
+static void deduplicate_recursive(const struct DeDuplicateParams *p, uint i)
+{
+ const KDTreeNode *node = &p->nodes[i];
+ if (p->search_co[node->d] + p->range <= node->co[node->d]) {
+ if (node->left != KD_NODE_UNSET) {
+ deduplicate_recursive(p, node->left);
+ }
+ }
+ else if (p->search_co[node->d] - p->range >= node->co[node->d]) {
+ if (node->right != KD_NODE_UNSET) {
+ deduplicate_recursive(p, node->right);
+ }
+ }
+ else {
+ if ((p->search != node->index) && (p->duplicates[node->index] == -1)) {
+ if (compare_len_squared_v3v3(node->co, p->search_co, p->range_sq)) {
+ p->duplicates[node->index] = (int)p->search;
+ *p->duplicates_found += 1;
+ }
+ }
+ if (node->left != KD_NODE_UNSET) {
+ deduplicate_recursive(p, node->left);
+ }
+ if (node->right != KD_NODE_UNSET) {
+ deduplicate_recursive(p, node->right);
+ }
+ }
+}
+
+/**
+ * Find duplicate points in \a range.
+ * Favors speed over quality since it doesn't find the best target vertex for merging.
+ * Nodes are looped over, duplicates are added when found.
+ * Nevertheless results are predictable.
+ *
+ * \param range: Coordinates in this range are candidates to be merged.
+ * \param use_index_order: Loop over the coordinates ordered by #KDTreeNode.index
+ * At the expense of some performance, this ensures the layout of the tree doesn't influence
+ * the iteration order.
+ * \param duplicates: An array of int's the length of #KDTree.totnode
+ * Values initialized to -1 are candidates to me merged.
+ * Setting the index to it's own position in the array prevents it from being touched,
+ * although it can still be used as a target.
+ * \returns The numebr of merges found (includes any merges already in the \a duplicates array).
+ *
+ * \note Merging is always a single step (target indices wont be marked for merging).
+ */
+int BLI_kdtree_calc_duplicates_fast(
+ const KDTree *tree, const float range, bool use_index_order,
+ int *duplicates)
+{
+ int found = 0;
+ struct DeDuplicateParams p = {
+ .nodes = tree->nodes,
+ .range = range,
+ .range_sq = range * range,
+ .duplicates = duplicates,
+ .duplicates_found = &found,
+ };
+
+ if (use_index_order) {
+ uint *order = kdtree_order(tree);
+ for (uint i = 0; i < tree->totnode; i++) {
+ const uint node_index = order[i];
+ const int index = (int)i;
+ if (ELEM(duplicates[index], -1, index)) {
+ p.search = index;
+ copy_v3_v3(p.search_co, tree->nodes[node_index].co);
+ deduplicate_recursive(&p, tree->root);
+ }
+ }
+ MEM_freeN(order);
+ }
+ else {
+ for (uint i = 0; i < tree->totnode; i++) {
+ const uint node_index = i;
+ const int index = p.nodes[node_index].index;
+ if (ELEM(duplicates[index], -1, index)) {
+ p.search = index;
+ copy_v3_v3(p.search_co, tree->nodes[node_index].co);
+ deduplicate_recursive(&p, tree->root);
+ }
+ }
+ }
+ return found;
+}
+
+/** \} */
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index 21ddddad32e..d3a63aceb89 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -217,15 +217,12 @@
/** \name Internal Structs
* \{ */
-typedef unsigned int uint;
-typedef unsigned char ubyte;
-
typedef uint64_t hash_key;
typedef struct BArrayInfo {
size_t chunk_stride;
- uint chunk_count;
+ // uint chunk_count; /* UNUSED (other values are derived from this) */
/* pre-calculated */
size_t chunk_byte_size;
@@ -291,7 +288,7 @@ typedef struct BChunkList {
/* a chunk of an array */
typedef struct BChunk {
- const ubyte *data;
+ const uchar *data;
size_t data_len;
/** number of #BChunkList using this. */
int users;
@@ -332,7 +329,7 @@ static size_t bchunk_list_size(const BChunkList *chunk_list);
* \{ */
static BChunk *bchunk_new(
- BArrayMemory *bs_mem, const ubyte *data, const size_t data_len)
+ BArrayMemory *bs_mem, const uchar *data, const size_t data_len)
{
BChunk *chunk = BLI_mempool_alloc(bs_mem->chunk);
chunk->data = data;
@@ -345,9 +342,9 @@ static BChunk *bchunk_new(
}
static BChunk *bchunk_new_copydata(
- BArrayMemory *bs_mem, const ubyte *data, const size_t data_len)
+ BArrayMemory *bs_mem, const uchar *data, const size_t data_len)
{
- ubyte *data_copy = MEM_mallocN(data_len, __func__);
+ uchar *data_copy = MEM_mallocN(data_len, __func__);
memcpy(data_copy, data, data_len);
return bchunk_new(bs_mem, data_copy, data_len);
}
@@ -367,7 +364,7 @@ static void bchunk_decref(
static bool bchunk_data_compare(
const BChunk *chunk,
- const ubyte *data_base, const size_t data_base_len,
+ const uchar *data_base, const size_t data_base_len,
const size_t offset)
{
if (offset + (size_t)chunk->data_len <= data_base_len) {
@@ -426,14 +423,14 @@ static void bchunk_list_decref(
#ifdef USE_VALIDATE_LIST_DATA_PARTIAL
static size_t bchunk_list_data_check(
- const BChunkList *chunk_list, const ubyte *data)
+ const BChunkList *chunk_list, const uchar *data)
{
- size_t total_size = 0;
+ size_t offset = 0;
for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
- if (memcmp(&data[total_size], cref->link->data, cref->link->data_len) != 0) {
+ if (memcmp(&data[offset], cref->link->data, cref->link->data_len) != 0) {
return false;
}
- total_size += cref->link->data_len;
+ offset += cref->link->data_len;
}
return true;
}
@@ -466,7 +463,7 @@ static void bchunk_list_ensure_min_size_last(
chunk_list->chunk_refs.last = cref->prev;
chunk_list->chunk_refs_len -= 1;
- ubyte *data_merge = MEM_mallocN(data_merge_len, __func__);
+ uchar *data_merge = MEM_mallocN(data_merge_len, __func__);
memcpy(data_merge, chunk_prev->data, chunk_prev->data_len);
memcpy(&data_merge[chunk_prev->data_len], chunk_curr->data, chunk_curr->data_len);
@@ -487,8 +484,8 @@ static void bchunk_list_ensure_min_size_last(
/* merge and split */
const size_t data_prev_len = split;
const size_t data_curr_len = data_merge_len - split;
- ubyte *data_prev = MEM_mallocN(data_prev_len, __func__);
- ubyte *data_curr = MEM_mallocN(data_curr_len, __func__);
+ uchar *data_prev = MEM_mallocN(data_prev_len, __func__);
+ uchar *data_curr = MEM_mallocN(data_curr_len, __func__);
if (data_prev_len <= chunk_prev->data_len) {
const size_t data_curr_shrink_len = chunk_prev->data_len - data_prev_len;
@@ -597,11 +594,10 @@ static void bchunk_list_append_only(
static void bchunk_list_append_data(
const BArrayInfo *info, BArrayMemory *bs_mem,
BChunkList *chunk_list,
- const ubyte *data, const size_t data_len)
+ const uchar *data, const size_t data_len)
{
BLI_assert(data_len != 0);
- // printf("data_len: %d\n", data_len);
#ifdef USE_MERGE_CHUNKS
BLI_assert(data_len <= info->chunk_byte_size_max);
@@ -613,13 +609,13 @@ static void bchunk_list_append_data(
const size_t data_merge_len = chunk_prev->data_len + data_len;
/* realloc for single user */
if (cref->link->users == 1) {
- ubyte *data_merge = MEM_reallocN((void *)cref->link->data, data_merge_len);
+ uchar *data_merge = MEM_reallocN((void *)cref->link->data, data_merge_len);
memcpy(&data_merge[chunk_prev->data_len], data, data_len);
cref->link->data = data_merge;
cref->link->data_len = data_merge_len;
}
else {
- ubyte *data_merge = MEM_mallocN(data_merge_len, __func__);
+ uchar *data_merge = MEM_mallocN(data_merge_len, __func__);
memcpy(data_merge, chunk_prev->data, chunk_prev->data_len);
memcpy(&data_merge[chunk_prev->data_len], data, data_len);
cref->link = bchunk_new(bs_mem, data_merge, data_merge_len);
@@ -639,7 +635,7 @@ static void bchunk_list_append_data(
/* don't run this, instead preemptively avoid creating a chunk only to merge it (above). */
#if 0
#ifdef USE_MERGE_CHUNKS
- bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list, chunk_size_min);
+ bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list);
#endif
#endif
}
@@ -654,7 +650,7 @@ static void bchunk_list_append_data(
static void bchunk_list_append_data_n(
const BArrayInfo *info, BArrayMemory *bs_mem,
BChunkList *chunk_list,
- const ubyte *data, size_t data_len)
+ const uchar *data, size_t data_len)
{
size_t data_trim_len, data_last_chunk_len;
bchunk_list_calc_trim_len(info, data_len, &data_trim_len, &data_last_chunk_len);
@@ -714,7 +710,7 @@ static void bchunk_list_append(
static void bchunk_list_fill_from_array(
const BArrayInfo *info, BArrayMemory *bs_mem,
BChunkList *chunk_list,
- const ubyte *data,
+ const uchar *data,
const size_t data_len)
{
BLI_assert(BLI_listbase_is_empty(&chunk_list->chunk_refs));
@@ -765,13 +761,13 @@ static void bchunk_list_fill_from_array(
#define HASH_INIT (5381)
-BLI_INLINE uint hash_data_single(const ubyte p)
+BLI_INLINE uint hash_data_single(const uchar p)
{
return (HASH_INIT << 5) + HASH_INIT + (unsigned int)p;
}
/* hash bytes, from BLI_ghashutil_strhash_n */
-static uint hash_data(const ubyte *key, size_t n)
+static uint hash_data(const uchar *key, size_t n)
{
const signed char *p;
unsigned int h = HASH_INIT;
@@ -788,7 +784,7 @@ static uint hash_data(const ubyte *key, size_t n)
#ifdef USE_HASH_TABLE_ACCUMULATE
static void hash_array_from_data(
- const BArrayInfo *info, const ubyte *data_slice, const size_t data_slice_len,
+ const BArrayInfo *info, const uchar *data_slice, const size_t data_slice_len,
hash_key *hash_array)
{
if (info->chunk_stride != 1) {
@@ -877,12 +873,12 @@ static void hash_accum_single(hash_key *hash_array, const size_t hash_array_len,
static hash_key key_from_chunk_ref(
const BArrayInfo *info, const BChunkRef *cref,
- /* avoid reallicating each time */
+ /* avoid reallocating each time */
hash_key *hash_store, const size_t hash_store_len)
{
/* in C, will fill in a reusable array */
BChunk *chunk = cref->link;
- BLI_assert(info->accum_read_ahead_bytes * info->chunk_stride);
+ BLI_assert((info->accum_read_ahead_bytes * info->chunk_stride) != 0);
if (info->accum_read_ahead_bytes <= chunk->data_len) {
hash_key key;
@@ -899,7 +895,7 @@ static hash_key key_from_chunk_ref(
key = hash_store[0];
/* cache the key */
- if (key == HASH_TABLE_KEY_UNSET) {
+ if (UNLIKELY(key == HASH_TABLE_KEY_UNSET)) {
key = HASH_TABLE_KEY_FALLBACK;
}
chunk->key = key;
@@ -929,12 +925,12 @@ static hash_key key_from_chunk_ref(
static const BChunkRef *table_lookup(
const BArrayInfo *info, BTableRef **table, const size_t table_len, const size_t i_table_start,
- const ubyte *data, const size_t data_len, const size_t offset, const hash_key *table_hash_array)
+ const uchar *data, const size_t data_len, const size_t offset, const hash_key *table_hash_array)
{
size_t size_left = data_len - offset;
hash_key key = table_hash_array[((offset - i_table_start) / info->chunk_stride)];
size_t key_index = (size_t)(key % (hash_key)table_len);
- for (BTableRef *tref = table[key_index]; tref; tref = tref->next) {
+ for (const BTableRef *tref = table[key_index]; tref; tref = tref->next) {
const BChunkRef *cref = tref->cref;
#ifdef USE_HASH_TABLE_KEY_CACHE
if (cref->link->key == key)
@@ -985,7 +981,7 @@ static hash_key key_from_chunk_ref(const BArrayInfo *info, const BChunkRef *cref
static const BChunkRef *table_lookup(
const BArrayInfo *info, BTableRef **table, const size_t table_len, const uint UNUSED(i_table_start),
- const ubyte *data, const size_t data_len, const size_t offset, const hash_key *UNUSED(table_hash_array))
+ const uchar *data, const size_t data_len, const size_t offset, const hash_key *UNUSED(table_hash_array))
{
const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride; /* TODO, cache */
@@ -1025,7 +1021,7 @@ static const BChunkRef *table_lookup(
*/
static BChunkList *bchunk_list_from_data_merge(
const BArrayInfo *info, BArrayMemory *bs_mem,
- const ubyte *data, const size_t data_len_original,
+ const uchar *data, const size_t data_len_original,
const BChunkList *chunk_list_reference)
{
ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size);
@@ -1042,10 +1038,8 @@ static BChunkList *bchunk_list_from_data_merge(
size_t i_prev = 0;
#ifdef USE_FASTPATH_CHUNKS_FIRST
- bool full_match = false;
-
{
- full_match = true;
+ bool full_match = true;
const BChunkRef *cref = chunk_list_reference->chunk_refs.first;
while (i_prev < data_len_original) {
@@ -1433,7 +1427,7 @@ BArrayStore *BLI_array_store_create(
BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__);
bs->info.chunk_stride = stride;
- bs->info.chunk_count = chunk_count;
+ // bs->info.chunk_count = chunk_count;
bs->info.chunk_byte_size = chunk_count * stride;
#ifdef USE_MERGE_CHUNKS
@@ -1566,7 +1560,7 @@ BArrayState *BLI_array_store_state_add(
const void *data, const size_t data_len,
const BArrayState *state_reference)
{
- /* ensure we're aligned to the stride */
+ /* ensure we're aligned to the stride */
BLI_assert((data_len % bs->info.chunk_stride) == 0);
#ifdef USE_PARANOID_CHECKS
@@ -1579,7 +1573,7 @@ BArrayState *BLI_array_store_state_add(
if (state_reference) {
chunk_list = bchunk_list_from_data_merge(
&bs->info, &bs->memory,
- (const ubyte *)data, data_len,
+ (const uchar *)data, data_len,
/* re-use reference chunks */
state_reference->chunk_list);
}
@@ -1588,7 +1582,7 @@ BArrayState *BLI_array_store_state_add(
bchunk_list_fill_from_array(
&bs->info, &bs->memory,
chunk_list,
- (const ubyte *)data, data_len);
+ (const uchar *)data, data_len);
}
chunk_list->users += 1;
@@ -1655,7 +1649,7 @@ void BLI_array_store_state_data_get(
BLI_assert(data_test_len == state->chunk_list->total_size);
#endif
- ubyte *data_step = (ubyte *)data;
+ uchar *data_step = (uchar *)data;
for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) {
BLI_assert(cref->link->users > 0);
memcpy(data_step, cref->link->data, cref->link->data_len);
diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c
index afc54511d13..e77e8cf40d0 100644
--- a/source/blender/blenlib/intern/bitmap_draw_2d.c
+++ b/source/blender/blenlib/intern/bitmap_draw_2d.c
@@ -46,6 +46,8 @@
/**
* Plot a line from \a p1 to \a p2 (inclusive).
+ *
+ * \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509
*/
void BLI_bitmap_draw_2d_line_v2v2i(
const int p1[2], const int p2[2],
@@ -57,33 +59,36 @@ void BLI_bitmap_draw_2d_line_v2v2i(
int x2 = p2[0];
int y2 = p2[1];
- int ix;
- int iy;
-
- /* if x1 == x2 or y1 == y2, then it does not matter what we set here */
- int delta_x = (x2 > x1 ? ((void)(ix = 1), x2 - x1) : ((void)(ix = -1), x1 - x2)) << 1;
- int delta_y = (y2 > y1 ? ((void)(iy = 1), y2 - y1) : ((void)(iy = -1), y1 - y2)) << 1;
-
if (callback(x1, y1, userData) == 0) {
return;
}
+ /* if x1 == x2 or y1 == y2, then it does not matter what we set here */
+ const int sign_x = (x2 > x1) ? 1 : -1;
+ const int sign_y = (y2 > y1) ? 1 : -1;
+
+ const int delta_x = (sign_x == 1) ? (x2 - x1) : (x1 - x2);
+ const int delta_y = (sign_y == 1) ? (y2 - y1) : (y1 - y2);
+
+ const int delta_x_step = delta_x * 2;
+ const int delta_y_step = delta_y * 2;
+
if (delta_x >= delta_y) {
/* error may go below zero */
- int error = delta_y - (delta_x >> 1);
+ int error = delta_y_step - delta_x;
while (x1 != x2) {
if (error >= 0) {
- if (error || (ix > 0)) {
- y1 += iy;
- error -= delta_x;
+ if (error || (sign_x == 1)) {
+ y1 += sign_y;
+ error -= delta_x_step;
}
/* else do nothing */
}
/* else do nothing */
- x1 += ix;
- error += delta_y;
+ x1 += sign_x;
+ error += delta_y_step;
if (callback(x1, y1, userData) == 0) {
return;
@@ -92,20 +97,20 @@ void BLI_bitmap_draw_2d_line_v2v2i(
}
else {
/* error may go below zero */
- int error = delta_x - (delta_y >> 1);
+ int error = delta_x_step - delta_y;
while (y1 != y2) {
if (error >= 0) {
- if (error || (iy > 0)) {
- x1 += ix;
- error -= delta_y;
+ if (error || (sign_y == 1)) {
+ x1 += sign_x;
+ error -= delta_y_step;
}
/* else do nothing */
}
/* else do nothing */
- y1 += iy;
- error += delta_x;
+ y1 += sign_y;
+ error += delta_x_step;
if (callback(x1, y1, userData) == 0) {
return;
diff --git a/source/blender/blenlib/intern/dynlib.c b/source/blender/blenlib/intern/dynlib.c
index b47c2ee60a6..51b91fb360f 100644
--- a/source/blender/blenlib/intern/dynlib.c
+++ b/source/blender/blenlib/intern/dynlib.c
@@ -50,7 +50,7 @@ struct DynamicLibrary {
#include "utf_winfunc.h"
#include "utfconv.h"
-DynamicLibrary *BLI_dynlib_open(char *name)
+DynamicLibrary *BLI_dynlib_open(const char *name)
{
DynamicLibrary *lib;
void *handle;
@@ -106,7 +106,7 @@ void BLI_dynlib_close(DynamicLibrary *lib)
#include <dlfcn.h>
-DynamicLibrary *BLI_dynlib_open(char *name)
+DynamicLibrary *BLI_dynlib_open(const char *name)
{
DynamicLibrary *lib;
void *handle = dlopen(name, RTLD_LAZY);
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index db4b3bcf20c..1df7f6f81e4 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -42,9 +42,6 @@
#include "zlib.h"
#ifdef WIN32
-# ifdef __MINGW32__
-# include <ctype.h>
-# endif
# include <io.h>
# include "BLI_winstuff.h"
# include "BLI_callbacks.h"
@@ -265,7 +262,7 @@ void *BLI_gzopen(const char *filename, const char *mode)
/* temporary #if until we update all libraries to 1.2.7
* for correct wide char path handling */
-#if ZLIB_VERNUM >= 0x1270 && !defined(FREE_WINDOWS)
+#if ZLIB_VERNUM >= 0x1270
UTF16_ENCODE(filename);
gzfile = gzopen_w(filename_16, mode);
diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c
index 8719c92a2a6..e990f0b663c 100644
--- a/source/blender/blenlib/intern/freetypefont.c
+++ b/source/blender/blenlib/intern/freetypefont.c
@@ -481,6 +481,22 @@ VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
return vfd;
}
+static void *vfontdata_copy_characters_value_cb(const void *src)
+{
+ return BLI_vfontchar_copy(src, 0);
+}
+
+VFontData *BLI_vfontdata_copy(const VFontData *vfont_src, const int UNUSED(flag))
+{
+ VFontData *vfont_dst = MEM_dupallocN(vfont_src);
+
+ if (vfont_src->characters != NULL) {
+ vfont_dst->characters = BLI_ghash_copy(vfont_src->characters, NULL, vfontdata_copy_characters_value_cb);
+ }
+
+ return vfont_dst;
+}
+
VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
{
VChar *che = NULL;
@@ -503,6 +519,20 @@ VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
return che;
}
+/* Yeah, this is very bad... But why is this in BLI in the first place, since it uses Nurb data?
+ * Anyway, do not feel like duplicating whole Nurb copy code here, so unless someone has a better idea... */
+#include "../../blenkernel/BKE_curve.h"
+
+VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int UNUSED(flag))
+{
+ VChar *vchar_dst = MEM_dupallocN(vchar_src);
+
+ BLI_listbase_clear(&vchar_dst->nurbsbase);
+ BKE_nurbList_duplicate(&vchar_dst->nurbsbase, &vchar_src->nurbsbase);
+
+ return vchar_dst;
+}
+
#if 0
/* Freetype2 Outline struct */
diff --git a/source/blender/blenlib/intern/hash_mm2a.c b/source/blender/blenlib/intern/hash_mm2a.c
index af6ef4f355f..e8ca9244f25 100644
--- a/source/blender/blenlib/intern/hash_mm2a.c
+++ b/source/blender/blenlib/intern/hash_mm2a.c
@@ -36,6 +36,8 @@
* for temporary data.
*/
+#include "BLI_compiler_attrs.h"
+
#include "BLI_hash_mm2a.h" /* own include */
/* Helpers. */
@@ -128,10 +130,10 @@ uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed)
switch (len) {
case 3:
h ^= data[2] << 16;
- /* fall through */
+ ATTR_FALLTHROUGH;
case 2:
h ^= data[1] << 8;
- /* fall through */
+ ATTR_FALLTHROUGH;
case 1:
h ^= data[0];
h *= MM2A_M;
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index c9bf4976ae8..46dcee48eda 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -342,6 +342,40 @@ void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
}
}
+
+/**
+ * Insert a link in place of another, without changing it's position in the list.
+ *
+ * Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
+ * - `vreplacelink` *must* be in the list.
+ * - `vnewlink` *must not* be in the list.
+ */
+void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
+{
+ Link *l_old = vreplacelink;
+ Link *l_new = vnewlink;
+
+ /* update adjacent links */
+ if (l_old->next != NULL) {
+ l_old->next->prev = l_new;
+ }
+ if (l_old->prev != NULL) {
+ l_old->prev->next = l_new;
+ }
+
+ /* set direct links */
+ l_new->next = l_old->next;
+ l_new->prev = l_old->prev;
+
+ /* update list */
+ if (listbase->first == l_old) {
+ listbase->first = l_new;
+ }
+ if (listbase->last == l_old) {
+ listbase->last = l_new;
+ }
+}
+
/**
* Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
* item if new position would exceed list (could optionally move to head/tail).
@@ -630,7 +664,7 @@ void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
}
/**
- * Returns the 1-based index of the first element of listbase which contains the specified
+ * Returns the 0-based index of the first element of listbase which contains the specified
* null-terminated string at the specified offset, or -1 if not found.
*/
int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset)
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 8d2d80c2a35..749c18fc0ce 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -33,6 +33,7 @@
#include <float.h>
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
#ifdef __SSE2__
# include <emmintrin.h>
@@ -181,11 +182,59 @@ MINLINE unsigned power_of_2_min_u(unsigned x)
return x - (x >> 1);
}
-MINLINE int iroundf(float a)
-{
- return (int)floorf(a + 0.5f);
+/* rounding and clamping */
+
+#define _round_clamp_fl_impl(arg, ty, min, max) { \
+ float r = floorf(arg + 0.5f); \
+ if (UNLIKELY(r <= (float)min)) return (ty)min; \
+ else if (UNLIKELY(r >= (float)max)) return (ty)max; \
+ else return (ty)r; \
+}
+
+#define _round_clamp_db_impl(arg, ty, min, max) { \
+ double r = floor(arg + 0.5); \
+ if (UNLIKELY(r <= (double)min)) return (ty)min; \
+ else if (UNLIKELY(r >= (double)max)) return (ty)max; \
+ else return (ty)r; \
}
+#define _round_fl_impl(arg, ty) { return (ty)floorf(arg + 0.5f); }
+#define _round_db_impl(arg, ty) { return (ty)floor(arg + 0.5); }
+
+MINLINE signed char round_fl_to_char(float a) { _round_fl_impl(a, signed char) }
+MINLINE unsigned char round_fl_to_uchar(float a) { _round_fl_impl(a, unsigned char) }
+MINLINE short round_fl_to_short(float a) { _round_fl_impl(a, short) }
+MINLINE unsigned short round_fl_to_ushort(float a) { _round_fl_impl(a, unsigned short) }
+MINLINE int round_fl_to_int(float a) { _round_fl_impl(a, int) }
+MINLINE unsigned int round_fl_to_uint(float a) { _round_fl_impl(a, unsigned int) }
+
+MINLINE signed char round_db_to_char(double a) { _round_db_impl(a, signed char) }
+MINLINE unsigned char round_db_to_uchar(double a) { _round_db_impl(a, unsigned char) }
+MINLINE short round_db_to_short(double a) { _round_db_impl(a, short) }
+MINLINE unsigned short round_db_to_ushort(double a) { _round_db_impl(a, unsigned short) }
+MINLINE int round_db_to_int(double a) { _round_db_impl(a, int) }
+MINLINE unsigned int round_db_to_uint(double a) { _round_db_impl(a, unsigned int) }
+
+#undef _round_fl_impl
+#undef _round_db_impl
+
+MINLINE signed char round_fl_to_char_clamp(float a) { _round_clamp_fl_impl(a, signed char, SCHAR_MIN, SCHAR_MAX) }
+MINLINE unsigned char round_fl_to_uchar_clamp(float a) { _round_clamp_fl_impl(a, unsigned char, 0, UCHAR_MAX) }
+MINLINE short round_fl_to_short_clamp(float a) { _round_clamp_fl_impl(a, short, SHRT_MIN, SHRT_MAX) }
+MINLINE unsigned short round_fl_to_ushort_clamp(float a) { _round_clamp_fl_impl(a, unsigned short, 0, USHRT_MAX) }
+MINLINE int round_fl_to_int_clamp(float a) { _round_clamp_fl_impl(a, int, INT_MIN, INT_MAX) }
+MINLINE unsigned int round_fl_to_uint_clamp(float a) { _round_clamp_fl_impl(a, unsigned int, 0, UINT_MAX) }
+
+MINLINE signed char round_db_to_char_clamp(double a) { _round_clamp_db_impl(a, signed char, SCHAR_MIN, SCHAR_MAX) }
+MINLINE unsigned char round_db_to_uchar_clamp(double a) { _round_clamp_db_impl(a, unsigned char, 0, UCHAR_MAX) }
+MINLINE short round_db_to_short_clamp(double a) { _round_clamp_db_impl(a, short, SHRT_MIN, SHRT_MAX) }
+MINLINE unsigned short round_db_to_ushort_clamp(double a) { _round_clamp_db_impl(a, unsigned short, 0, USHRT_MAX) }
+MINLINE int round_db_to_int_clamp(double a) { _round_clamp_db_impl(a, int, INT_MIN, INT_MAX) }
+MINLINE unsigned int round_db_to_uint_clamp(double a) { _round_clamp_db_impl(a, unsigned int, 0, UINT_MAX) }
+
+#undef _round_clamp_fl_impl
+#undef _round_clamp_db_impl
+
/* integer division that rounds 0.5 up, particularly useful for color blending
* with integers, to avoid gradual darkening when rounding down */
MINLINE int divide_round_i(int a, int b)
@@ -194,6 +243,17 @@ MINLINE int divide_round_i(int a, int b)
}
/**
+ * Integer division that floors negative result.
+ * \note This works like Python's int division.
+ */
+MINLINE int divide_floor_i(int a, int b)
+{
+ int d = a / b;
+ int r = a % b; /* Optimizes into a single division. */
+ return r ? d - ((a < 0) ^ (b < 0)) : d;
+}
+
+/**
* modulo that handles negative numbers, works the same as Python's.
*/
MINLINE int mod_i(int i, int n)
@@ -314,6 +374,21 @@ MINLINE int signum_i(float a)
else return 0;
}
+/** Returns number of (base ten) *significant* digits of integer part of given float
+ * (negative in case of decimal-only floats, 0.01 returns -1 e.g.). */
+MINLINE int integer_digits_f(const float f)
+{
+ return (f == 0.0f) ? 0 : (int)floor(log10(fabs(f))) + 1;
+}
+
+/** Returns number of (base ten) *significant* digits of integer part of given double
+ * (negative in case of decimal-only floats, 0.01 returns -1 e.g.). */
+MINLINE int integer_digits_d(const double d)
+{
+ return (d == 0.0) ? 0 : (int)floor(log10(fabs(d))) + 1;
+}
+
+
/* Internal helpers for SSE2 implementation.
*
* NOTE: Are to be called ONLY from inside `#ifdef __SSE2__` !!!
diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c
index 048ab71c6dc..dc3874f83a2 100644
--- a/source/blender/blenlib/intern/math_color_blend_inline.c
+++ b/source/blender/blenlib/intern/math_color_blend_inline.c
@@ -444,7 +444,7 @@ MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const ch
else if (src2[i] == 0) {
temp = 0;
}
- else if (src2[i] > 127) {
+ else if (src2[i] > 127) {
temp = min_ii(((src1[i]) * 255) / (2 * (255 - src2[i])), 255);
}
else {
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index f31d0935b77..d3080e5530f 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -37,20 +37,6 @@
/********************************** Polygons *********************************/
-void cent_tri_v3(float cent[3], const float v1[3], const float v2[3], const float v3[3])
-{
- cent[0] = (v1[0] + v2[0] + v3[0]) / 3.0f;
- cent[1] = (v1[1] + v2[1] + v3[1]) / 3.0f;
- cent[2] = (v1[2] + v2[2] + v3[2]) / 3.0f;
-}
-
-void cent_quad_v3(float cent[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
-{
- cent[0] = 0.25f * (v1[0] + v2[0] + v3[0] + v4[0]);
- cent[1] = 0.25f * (v1[1] + v2[1] + v3[1] + v4[1]);
- cent[2] = 0.25f * (v1[2] + v2[2] + v3[2] + v4[2]);
-}
-
void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
{
float n1[3], n2[3];
@@ -586,8 +572,8 @@ float dist_squared_to_ray_v3(
}
/**
* 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.
+ * \param r_point: Is the point on segment closest to ray (or to ray_origin if the ray and the segment are parallel).
+ * \param r_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],
@@ -633,6 +619,152 @@ float dist_squared_ray_to_seg_v3(
return len_squared_v3(t) - SQUARE(*r_depth);
}
+/* -------------------------------------------------------------------- */
+/** \name dist_squared_to_ray_to_aabb and helpers
+ * \{ */
+
+void dist_squared_ray_to_aabb_v3_precalc(
+ struct DistRayAABB_Precalc *neasrest_precalc,
+ const float ray_origin[3], const float ray_direction[3])
+{
+ copy_v3_v3(neasrest_precalc->ray_origin, ray_origin);
+ copy_v3_v3(neasrest_precalc->ray_direction, ray_direction);
+
+ for (int i = 0; i < 3; i++) {
+ neasrest_precalc->ray_inv_dir[i] =
+ (neasrest_precalc->ray_direction[i] != 0.0f) ?
+ (1.0f / neasrest_precalc->ray_direction[i]) : FLT_MAX;
+ neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f);
+ }
+}
+
+/**
+ * Returns the distance from a ray to a bound-box (projected on ray)
+ */
+float dist_squared_ray_to_aabb_v3(
+ const struct DistRayAABB_Precalc *data,
+ const float bb_min[3], const float bb_max[3],
+ float r_point[3], float *r_depth)
+{
+ // bool r_axis_closest[3];
+ float local_bvmin[3], local_bvmax[3];
+ if (data->sign[0]) {
+ local_bvmin[0] = bb_max[0];
+ local_bvmax[0] = bb_min[0];
+ }
+ else {
+ local_bvmin[0] = bb_min[0];
+ local_bvmax[0] = bb_max[0];
+ }
+ if (data->sign[1]) {
+ local_bvmin[1] = bb_max[1];
+ local_bvmax[1] = bb_min[1];
+ }
+ else {
+ local_bvmin[1] = bb_min[1];
+ local_bvmax[1] = bb_max[1];
+ }
+ if (data->sign[2]) {
+ local_bvmin[2] = bb_max[2];
+ local_bvmax[2] = bb_min[2];
+ }
+ else {
+ local_bvmin[2] = bb_min[2];
+ local_bvmax[2] = bb_max[2];
+ }
+
+ const float tmin[3] = {
+ (local_bvmin[0] - data->ray_origin[0]) * data->ray_inv_dir[0],
+ (local_bvmin[1] - data->ray_origin[1]) * data->ray_inv_dir[1],
+ (local_bvmin[2] - data->ray_origin[2]) * data->ray_inv_dir[2],
+ };
+ const float tmax[3] = {
+ (local_bvmax[0] - data->ray_origin[0]) * data->ray_inv_dir[0],
+ (local_bvmax[1] - data->ray_origin[1]) * data->ray_inv_dir[1],
+ (local_bvmax[2] - data->ray_origin[2]) * data->ray_inv_dir[2],
+ };
+ /* `va` and `vb` are the coordinates of the AABB edge closest to the ray */
+ float va[3], vb[3];
+ /* `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB */
+ float rtmin, rtmax;
+ int main_axis;
+
+ if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
+ rtmax = tmax[0];
+ va[0] = vb[0] = local_bvmax[0];
+ main_axis = 3;
+ // r_axis_closest[0] = data->sign[0];
+ }
+ else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
+ rtmax = tmax[1];
+ va[1] = vb[1] = local_bvmax[1];
+ main_axis = 2;
+ // r_axis_closest[1] = data->sign[1];
+ }
+ else {
+ rtmax = tmax[2];
+ va[2] = vb[2] = local_bvmax[2];
+ main_axis = 1;
+ // r_axis_closest[2] = data->sign[2];
+ }
+
+ if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
+ rtmin = tmin[0];
+ va[0] = vb[0] = local_bvmin[0];
+ main_axis -= 3;
+ // r_axis_closest[0] = !data->sign[0];
+ }
+ else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
+ rtmin = tmin[1];
+ va[1] = vb[1] = local_bvmin[1];
+ main_axis -= 1;
+ // r_axis_closest[1] = !data->sign[1];
+ }
+ else {
+ rtmin = tmin[2];
+ va[2] = vb[2] = local_bvmin[2];
+ main_axis -= 2;
+ // r_axis_closest[2] = !data->sign[2];
+ }
+ if (main_axis < 0) {
+ main_axis += 3;
+ }
+
+ /* if rtmin <= rtmax, ray intersect `AABB` */
+ if (rtmin <= rtmax) {
+ float dvec[3];
+ copy_v3_v3(r_point, local_bvmax);
+ sub_v3_v3v3(dvec, local_bvmax, data->ray_origin);
+ *r_depth = dot_v3v3(dvec, data->ray_direction);
+ return 0.0f;
+ }
+
+ if (data->sign[main_axis]) {
+ va[main_axis] = local_bvmax[main_axis];
+ vb[main_axis] = local_bvmin[main_axis];
+ }
+ else {
+ va[main_axis] = local_bvmin[main_axis];
+ vb[main_axis] = local_bvmax[main_axis];
+ }
+
+ return dist_squared_ray_to_seg_v3(
+ data->ray_origin, data->ray_direction, va, vb,
+ r_point, r_depth);
+}
+
+float dist_squared_ray_to_aabb_v3_simple(
+ const float ray_origin[3], const float ray_direction[3],
+ const float bbmin[3], const float bbmax[3],
+ float r_point[3], float *r_depth)
+{
+ struct DistRayAABB_Precalc data;
+ dist_squared_ray_to_aabb_v3_precalc(&data, ray_origin, ray_direction);
+ return dist_squared_ray_to_aabb_v3(&data, bbmin, bbmax, r_point, r_depth);
+}
+/** \} */
+
+
/* Adapted from "Real-Time Collision Detection" by Christer Ericson,
* published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc.
*
@@ -779,18 +911,29 @@ int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], co
return ISECT_LINE_LINE_NONE;
}
-/* get intersection point of two 2D segments and return intersection type:
- * -1: collinear
- * 1: intersection
+/**
+ * Get intersection point of two 2D segments.
+ *
+ * \param endpoint_bias: Bias to use when testing for end-point overlap.
+ * A positive value considers intersections that extend past the endpoints,
+ * negative values contract the endpoints.
+ * Note the bias is applied to a 0-1 factor, not scaled to the length of segments.
+ *
+ * \returns intersection type:
+ * - -1: collinear.
+ * - 1: intersection.
+ * - 0: no intersection.
*/
-int isect_seg_seg_v2_point(
+int isect_seg_seg_v2_point_ex(
const float v0[2], const float v1[2],
const float v2[2], const float v3[2],
+ const float endpoint_bias,
float r_vi[2])
{
float s10[2], s32[2], s30[2], d;
const float eps = 1e-6f;
- const float eps_sq = eps * eps;
+ const float endpoint_min = -endpoint_bias;
+ const float endpoint_max = endpoint_bias + 1.0f;
sub_v2_v2v2(s10, v1, v0);
sub_v2_v2v2(s32, v3, v2);
@@ -804,8 +947,8 @@ int isect_seg_seg_v2_point(
u = cross_v2v2(s30, s32) / d;
v = cross_v2v2(s10, s30) / d;
- if ((u >= -eps && u <= 1.0f + eps) &&
- (v >= -eps && v <= 1.0f + eps))
+ if ((u >= endpoint_min && u <= endpoint_max) &&
+ (v >= endpoint_min && v <= endpoint_max))
{
/* intersection */
float vi_test[2];
@@ -824,7 +967,7 @@ int isect_seg_seg_v2_point(
sub_v2_v2v2(s_vi_v2, vi_test, v2);
v = (dot_v2v2(s32, s_vi_v2) / dot_v2v2(s32, s32));
#endif
- if (v >= -eps && v <= 1.0f + eps) {
+ if (v >= endpoint_min && v <= endpoint_max) {
copy_v2_v2(r_vi, vi_test);
return 1;
}
@@ -842,7 +985,7 @@ int isect_seg_seg_v2_point(
float u_a, u_b;
if (equals_v2v2(v0, v1)) {
- if (len_squared_v2v2(v2, v3) > eps_sq) {
+ if (len_squared_v2v2(v2, v3) > SQUARE(eps)) {
/* use non-point segment as basis */
SWAP(const float *, v0, v2);
SWAP(const float *, v1, v3);
@@ -869,7 +1012,7 @@ int isect_seg_seg_v2_point(
if (u_a > u_b)
SWAP(float, u_a, u_b);
- if (u_a > 1.0f + eps || u_b < -eps) {
+ if (u_a > endpoint_max || u_b < endpoint_min) {
/* non-overlapping segments */
return -1;
}
@@ -885,6 +1028,15 @@ int isect_seg_seg_v2_point(
}
}
+int isect_seg_seg_v2_point(
+ const float v0[2], const float v1[2],
+ const float v2[2], const float v3[2],
+ float r_vi[2])
+{
+ const float endpoint_bias = 1e-6f;
+ return isect_seg_seg_v2_point_ex(v0, v1, v2, v3, endpoint_bias, r_vi);
+}
+
bool isect_seg_seg_v2_simple(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{
#define CCW(A, B, C) \
@@ -1842,7 +1994,7 @@ bool isect_tri_tri_epsilon_v3(
(range[0].max < range[1].min)) == 0)
{
if (r_i1 && r_i2) {
- project_plane_v3_v3v3(plane_co, plane_co, plane_no);
+ project_plane_normalized_v3_v3v3(plane_co, plane_co, plane_no);
madd_v3_v3v3fl(r_i1, plane_co, plane_no, max_ff(range[0].min, range[1].min));
madd_v3_v3v3fl(r_i2, plane_co, plane_no, min_ff(range[0].max, range[1].max));
}
@@ -2323,222 +2475,32 @@ bool isect_ray_aabb_v3(
return true;
}
-void dist_squared_ray_to_aabb_v3_precalc(
- struct NearestRayToAABB_Precalc *data,
- const float ray_origin[3], const float ray_direction[3])
-{
- float dir_sq[3];
-
- for (int i = 0; i < 3; i++) {
- data->ray_origin[i] = ray_origin[i];
- data->ray_direction[i] = ray_direction[i];
- data->ray_inv_dir[i] = (data->ray_direction[i] != 0.0f) ? (1.0f / data->ray_direction[i]) : FLT_MAX;
- /* It has to be a function of `ray_inv_dir`,
- * since the division of 1 by 0.0f, can be -inf or +inf */
- data->sign[i] = (data->ray_inv_dir[i] < 0.0f);
-
- dir_sq[i] = SQUARE(data->ray_direction[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->idiag_sq[0] = (diag_sq[0] > FLT_EPSILON) ? (1.0f / diag_sq[0]) : FLT_MAX;
- data->idiag_sq[1] = (diag_sq[1] > FLT_EPSILON) ? (1.0f / diag_sq[1]) : FLT_MAX;
- data->idiag_sq[2] = (diag_sq[2] > FLT_EPSILON) ? (1.0f / diag_sq[2]) : FLT_MAX;
-
- data->cdot_axis[0] = data->ray_direction[0] * data->idiag_sq[0];
- data->cdot_axis[1] = data->ray_direction[1] * data->idiag_sq[1];
- data->cdot_axis[2] = data->ray_direction[2] * data->idiag_sq[2];
-}
-
-/**
- * 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
+/*
+ * Test a bounding box (AABB) for ray intersection
+ * assumes the ray is already local to the boundbox space
*/
-float dist_squared_ray_to_aabb_v3(
- const struct NearestRayToAABB_Precalc *data,
+bool isect_ray_aabb_v3_simple(
+ const float orig[3], const float dir[3],
const float bb_min[3], const float bb_max[3],
- 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->sign[0] == 0) {
- local_bvmin[0] = bb_min[0] - data->ray_origin[0];
- local_bvmax[0] = bb_max[0] - data->ray_origin[0];
- }
- else {
- local_bvmin[0] = bb_max[0] - data->ray_origin[0];
- local_bvmax[0] = bb_min[0] - data->ray_origin[0];
- }
-
- if (data->sign[1] == 0) {
- local_bvmin[1] = bb_min[1] - data->ray_origin[1];
- local_bvmax[1] = bb_max[1] - data->ray_origin[1];
- }
- else {
- local_bvmin[1] = bb_max[1] - data->ray_origin[1];
- local_bvmax[1] = bb_min[1] - data->ray_origin[1];
- }
-
- if (data->sign[2] == 0) {
- local_bvmin[2] = bb_min[2] - data->ray_origin[2];
- local_bvmax[2] = bb_max[2] - data->ray_origin[2];
- }
- else {
- local_bvmin[2] = bb_max[2] - data->ray_origin[2];
- local_bvmax[2] = bb_min[2] - data->ray_origin[2];
- }
-
- 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, rdist;
- /* `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[0];
- main_axis = 3;
- r_axis_closest[0] = data->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[1];
- main_axis = 2;
- r_axis_closest[1] = data->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[2];
- main_axis = 1;
- r_axis_closest[2] = data->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[0];
- main_axis -= 3;
- r_axis_closest[0] = !data->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[1];
- main_axis -= 1;
- r_axis_closest[1] = !data->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[2];
- main_axis -= 2;
- r_axis_closest[2] = !data->sign[2];
- }
- /* *** end min/max axis *** */
-
-
- /* `if rtmax < 0`, the whole `AABB` is behing us */
- if ((rtmax < 0.0f) && (rtmin < 0.0f)) {
- return FLT_MAX;
- }
-
- if (main_axis < 0) {
- main_axis += 3;
- }
-
- if (data->sign[main_axis] == 0) {
- v1[main_axis] = local_bvmin[main_axis];
- v2[main_axis] = local_bvmax[main_axis];
- }
- else {
- v1[main_axis] = local_bvmax[main_axis];
- v2[main_axis] = local_bvmin[main_axis];
- }
-
- /* if rtmin < rtmax, ray intersect `AABB` */
- if (rtmin <= rtmax) {
- const float proj = rtmin * data->ray_direction[main_axis];
- rdist = 0.0f;
- r_axis_closest[main_axis] = (proj - v1[main_axis]) < (v2[main_axis] - proj);
- }
+ float *tmin, float *tmax)
+{
+ double t[7];
+ float hit_dist[2];
+ t[1] = (double)(bb_min[0] - orig[0]) / dir[0];
+ t[2] = (double)(bb_max[0] - orig[0]) / dir[0];
+ t[3] = (double)(bb_min[1] - orig[1]) / dir[1];
+ t[4] = (double)(bb_max[1] - orig[1]) / dir[1];
+ t[5] = (double)(bb_min[2] - orig[2]) / dir[2];
+ t[6] = (double)(bb_max[2] - orig[2]) / dir[2];
+ hit_dist[0] = (float)fmax(fmax(fmin(t[1], t[2]), fmin(t[3], t[4])), fmin(t[5], t[6]));
+ hit_dist[1] = (float)fmin(fmin(fmax(t[1], t[2]), fmax(t[3], t[4])), fmax(t[5], t[6]));
+ if ((hit_dist[1] < 0 || hit_dist[0] > hit_dist[1]))
+ return false;
else {
- /* `proj` equals to nearest point on the ray closest to the edge `v1 v2` of the `AABB`. */
- const float proj = mul * data->cdot_axis[main_axis];
- float depth;
- if (v1[main_axis] > proj) { /* the nearest point to the ray is the point v1 */
- /* `depth` is equivalent the distance from the origin to the point v1,
- * Here's a faster way to calculate the dot product of v1 and ray
- * (depth = dot_v3v3(v1, data->ray.direction))*/
- depth = mul + data->ray_direction[main_axis] * v1[main_axis];
- rdist = len_squared_v3(v1) - SQUARE(depth);
- r_axis_closest[main_axis] = true;
- }
- else if (v2[main_axis] < proj) { /* the nearest point of the ray is the point v2 */
- depth = mul + data->ray_direction[main_axis] * v2[main_axis];
- rdist = len_squared_v3(v2) - SQUARE(depth);
- r_axis_closest[main_axis] = false;
- }
- else { /* the nearest point of the ray is on the edge of the `AABB`. */
- float v[2];
- mul *= data->idiag_sq[main_axis];
- if (main_axis == 0) {
- v[0] = (mul * data->ray_direction[1]) - v1[1];
- v[1] = (mul * data->ray_direction[2]) - v1[2];
- }
- else if (main_axis == 1) {
- v[0] = (mul * data->ray_direction[0]) - v1[0];
- v[1] = (mul * data->ray_direction[2]) - v1[2];
- }
- else {
- v[0] = (mul * data->ray_direction[0]) - v1[0];
- v[1] = (mul * data->ray_direction[1]) - v1[1];
- }
- rdist = len_squared_v2(v);
- r_axis_closest[main_axis] = (proj - v1[main_axis]) < (v2[main_axis] - proj);
- }
+ if (tmin) *tmin = hit_dist[0];
+ if (tmax) *tmax = hit_dist[1];
+ return true;
}
-
- return rdist;
}
/* find closest point to p on line through (l1, l2) and return lambda,
@@ -2964,7 +2926,15 @@ static bool barycentric_weights(const float v1[3], const float v2[3], const floa
}
}
-void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3])
+void interp_weights_tri_v3(float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3])
+{
+ float n[3];
+
+ normal_tri_v3(n, v1, v2, v3);
+ barycentric_weights(v1, v2, v3, co, n, w);
+}
+
+void interp_weights_quad_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3])
{
float w2[3];
@@ -2977,7 +2947,7 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co
w[1] = 1.0f;
else if (equals_v3v3(co, v3))
w[2] = 1.0f;
- else if (v4 && equals_v3v3(co, v4))
+ else if (equals_v3v3(co, v4))
w[3] = 1.0f;
else {
/* otherwise compute barycentric interpolation weights */
@@ -2985,35 +2955,24 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co
bool degenerate;
sub_v3_v3v3(n1, v1, v3);
- if (v4) {
- sub_v3_v3v3(n2, v2, v4);
- }
- else {
- sub_v3_v3v3(n2, v2, v3);
- }
+ sub_v3_v3v3(n2, v2, v4);
cross_v3_v3v3(n, n1, n2);
- /* OpenGL seems to split this way, so we do too */
- if (v4) {
- degenerate = barycentric_weights(v1, v2, v4, co, n, w);
- SWAP(float, w[2], w[3]);
-
- if (degenerate || (w[0] < 0.0f)) {
- /* if w[1] is negative, co is on the other side of the v1-v3 edge,
- * so we interpolate using the other triangle */
- degenerate = barycentric_weights(v2, v3, v4, co, n, w2);
-
- if (!degenerate) {
- w[0] = 0.0f;
- w[1] = w2[0];
- w[2] = w2[1];
- w[3] = w2[2];
- }
+ degenerate = barycentric_weights(v1, v2, v4, co, n, w);
+ SWAP(float, w[2], w[3]);
+
+ if (degenerate || (w[0] < 0.0f)) {
+ /* if w[1] is negative, co is on the other side of the v1-v3 edge,
+ * so we interpolate using the other triangle */
+ degenerate = barycentric_weights(v2, v3, v4, co, n, w2);
+
+ if (!degenerate) {
+ w[0] = 0.0f;
+ w[1] = w2[0];
+ w[2] = w2[1];
+ w[3] = w2[2];
}
}
- else {
- barycentric_weights(v1, v2, v3, co, n, w);
- }
}
}
@@ -3058,6 +3017,9 @@ bool barycentric_coords_v2(const float v1[2], const float v2[2], const float v3[
/**
* \note: using #cross_tri_v2 means locations outside the triangle are correctly weighted
+ *
+ * \note This is *exactly* the same calculation as #resolve_tri_uv_v2,
+ * although it has double precision and is used for texture baking, so keep both.
*/
void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
@@ -3097,9 +3059,11 @@ void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const fl
}
}
-/* same as #barycentric_weights_v2 but works with a quad,
+/**
+ * same as #barycentric_weights_v2 but works with a quad,
* note: untested for values outside the quad's bounds
- * this is #interp_weights_poly_v2 expanded for quads only */
+ * this is #interp_weights_poly_v2 expanded for quads only
+ */
void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const float v3[2], const float v4[2],
const float co[2], float w[4])
{
@@ -3552,6 +3516,8 @@ void interp_cubic_v3(float x[3], float v[3], const float x1[3], const float v1[3
* Barycentric reverse
*
* Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
+ *
+ * \note same basic result as #barycentric_weights_v2, see it's comment for details.
*/
void resolve_tri_uv_v2(float r_uv[2], const float st[2],
const float st0[2], const float st1[2], const float st2[2])
@@ -3763,6 +3729,9 @@ void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3])
/***************************** View & Projection *****************************/
+/**
+ * Matches `glOrtho` result.
+ */
void orthographic_m4(float matrix[4][4], const float left, const float right, const float bottom, const float top,
const float nearClip, const float farClip)
{
@@ -3783,6 +3752,9 @@ void orthographic_m4(float matrix[4][4], const float left, const float right, co
matrix[3][2] = -(farClip + nearClip) / Zdelta;
}
+/**
+ * Matches `glFrustum` result.
+ */
void perspective_m4(float mat[4][4], const float left, const float right, const float bottom, const float top,
const float nearClip, const float farClip)
{
@@ -3917,10 +3889,9 @@ void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py
float sine, cosine, hyp, hyp1, dx, dy, dz;
float mat1[4][4];
- unit_m4(mat);
unit_m4(mat1);
- rotate_m4(mat, 'Z', -twist);
+ axis_angle_to_mat4_single(mat, 'Z', -twist);
dx = px - vx;
dy = py - vy;
@@ -4060,9 +4031,29 @@ void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const f
}
}
+void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3])
+{
+ float target[3] = {0.0f, 0.0f, 1.0f};
+ float axis[3];
+
+ cross_v3_v3v3(axis, no, target);
+ normalize_v3(axis);
+
+ map_to_plane_axis_angle_v2_v3v3fl(r_co, co, axis, angle_normalized_v3v3(no, target));
+}
+
+void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2], const float co[3], const float axis[3], const float angle)
+{
+ float tmp[3];
+
+ rotate_normalized_v3_v3v3fl(tmp, co, axis, angle);
+
+ copy_v2_v2(r_co, tmp);
+}
+
/********************************* Normals **********************************/
-void accumulate_vertex_normals_tri(
+void accumulate_vertex_normals_tri_v3(
float n1[3], float n2[3], float n3[3],
const float f_no[3],
const float co1[3], const float co2[3], const float co3[3])
@@ -4096,7 +4087,7 @@ void accumulate_vertex_normals_tri(
}
}
-void accumulate_vertex_normals(
+void accumulate_vertex_normals_v3(
float n1[3], float n2[3], float n3[3], float n4[3],
const float f_no[3],
const float co1[3], const float co2[3], const float co3[3], const float co4[3])
@@ -4140,7 +4131,7 @@ void accumulate_vertex_normals(
/* Add weighted face normal component into normals of the face vertices.
* Caller must pass pre-allocated vdiffs of nverts length. */
-void accumulate_vertex_normals_poly(float **vertnos, const float polyno[3],
+void accumulate_vertex_normals_poly_v3(float **vertnos, const float polyno[3],
const float **vertcos, float vdiffs[][3], const int nverts)
{
int i;
@@ -4171,7 +4162,7 @@ void accumulate_vertex_normals_poly(float **vertnos, const float polyno[3],
/********************************* Tangents **********************************/
-void tangent_from_uv(
+void tangent_from_uv_v3(
const float uv1[2], const float uv2[2], const float uv3[3],
const float co1[3], const float co2[3], const float co3[3],
const float n[3],
@@ -4213,30 +4204,28 @@ void tangent_from_uv(
/****************************** Vector Clouds ********************************/
/* vector clouds */
-/* void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, float (*rpos)[3], float *rweight,
- * float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3])
- *
+/**
* input
- * (
- * int list_size
- * 4 lists as pointer to array[list_size]
- * 1. current pos array of 'new' positions
- * 2. current weight array of 'new'weights (may be NULL pointer if you have no weights )
- * 3. reference rpos array of 'old' positions
- * 4. reference rweight array of 'old'weights (may be NULL pointer if you have no weights )
- * )
+ *
+ * \param list_size: 4 lists as pointer to array[list_size]
+ * \param pos: current pos array of 'new' positions
+ * \param weight: current weight array of 'new'weights (may be NULL pointer if you have no weights)
+ * \param rpos: Reference rpos array of 'old' positions
+ * \param rweight: Reference rweight array of 'old'weights (may be NULL pointer if you have no weights).
+ *
* output
- * (
- * float lloc[3] center of mass pos
- * float rloc[3] center of mass rpos
- * float lrot[3][3] rotation matrix
- * float lscale[3][3] scale matrix
+ *
+ * \param lloc: Center of mass pos.
+ * \param rloc: Center of mass rpos.
+ * \param lrot: Rotation matrix.
+ * \param lscale: Scale matrix.
+ *
* pointers may be NULL if not needed
- * )
*/
-void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, float (*rpos)[3], float *rweight,
- float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3])
+void vcloud_estimate_transform_v3(
+ const int list_size, const float (*pos)[3], const float *weight, const float (*rpos)[3], const float *rweight,
+ float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3])
{
float accu_com[3] = {0.0f, 0.0f, 0.0f}, accu_rcom[3] = {0.0f, 0.0f, 0.0f};
float accu_weight = 0.0f, accu_rweight = 0.0f;
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index c9c61d5c878..d1a219c196a 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -1625,53 +1625,50 @@ void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
mat[3][2] += (Tx * mat[0][2] + Ty * mat[1][2] + Tz * mat[2][2]);
}
+/**
+ * Rotate a matrix in-place.
+ *
+ * \note To create a new rotation matrix see:
+ * #axis_angle_to_mat4_single, #axis_angle_to_mat3_single, #angle_to_mat2
+ * (axis & angle args are compatible).
+ */
void rotate_m4(float mat[4][4], const char axis, const float angle)
{
- int col;
- float temp[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float cosine, sine;
+ const float angle_cos = cosf(angle);
+ const float angle_sin = sinf(angle);
assert(axis >= 'X' && axis <= 'Z');
- cosine = cosf(angle);
- sine = sinf(angle);
switch (axis) {
case 'X':
- for (col = 0; col < 4; col++)
- temp[col] = cosine * mat[1][col] + sine * mat[2][col];
- for (col = 0; col < 4; col++) {
- mat[2][col] = -sine * mat[1][col] + cosine * mat[2][col];
- mat[1][col] = temp[col];
+ for (int col = 0; col < 4; col++) {
+ float temp = angle_cos * mat[1][col] + angle_sin * mat[2][col];
+ mat[2][col] = -angle_sin * mat[1][col] + angle_cos * mat[2][col];
+ mat[1][col] = temp;
}
break;
case 'Y':
- for (col = 0; col < 4; col++)
- temp[col] = cosine * mat[0][col] - sine * mat[2][col];
- for (col = 0; col < 4; col++) {
- mat[2][col] = sine * mat[0][col] + cosine * mat[2][col];
- mat[0][col] = temp[col];
+ for (int col = 0; col < 4; col++) {
+ float temp = angle_cos * mat[0][col] - angle_sin * mat[2][col];
+ mat[2][col] = angle_sin * mat[0][col] + angle_cos * mat[2][col];
+ mat[0][col] = temp;
}
break;
case 'Z':
- for (col = 0; col < 4; col++)
- temp[col] = cosine * mat[0][col] + sine * mat[1][col];
- for (col = 0; col < 4; col++) {
- mat[1][col] = -sine * mat[0][col] + cosine * mat[1][col];
- mat[0][col] = temp[col];
+ for (int col = 0; col < 4; col++) {
+ float temp = angle_cos * mat[0][col] + angle_sin * mat[1][col];
+ mat[1][col] = -angle_sin * mat[0][col] + angle_cos * mat[1][col];
+ mat[0][col] = temp;
}
break;
+ default:
+ BLI_assert(0);
+ break;
}
}
-void rotate_m2(float mat[2][2], const float angle)
-{
- mat[0][0] = mat[1][1] = cosf(angle);
- mat[0][1] = sinf(angle);
- mat[1][0] = -mat[0][1];
-}
-
/**
* Scale or rotate around a pivot point,
* a convenience function to avoid having to do inline.
@@ -1744,16 +1741,16 @@ void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const floa
/**
* A polar-decomposition-based interpolation between matrix A and matrix B.
*
- * \note This code is about five times slower as the 'naive' interpolation done by \a blend_m3_m3m3
- * (it typically remains below 2 usec on an average i74700, while \a blend_m3_m3m3 remains below 0.4 usec).
+ * \note This code is about five times slower as the 'naive' interpolation done by #blend_m3_m3m3
+ * (it typically remains below 2 usec on an average i74700, while #blend_m3_m3m3 remains below 0.4 usec).
* However, it gives expected results even with non-uniformaly scaled matrices, see T46418 for an example.
*
* Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff
*
- * @return R the interpolated matrix.
- * @param A the intput matrix which is totally effective with \a t = 0.0.
- * @param B the intput matrix which is totally effective with \a t = 1.0.
- * @param t the interpolation factor.
+ * \param R: Resulting interpolated matrix.
+ * \param A: Input matrix which is totally effective with `t = 0.0`.
+ * \param B: Input matrix which is totally effective with `t = 1.0`.
+ * \param t: Interpolation factor.
*/
void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t)
{
@@ -1783,12 +1780,12 @@ void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t)
}
/**
- * Complete transform matrix interpolation, based on polar-decomposition-based interpolation from interp_m3_m3m3.
+ * Complete transform matrix interpolation, based on polar-decomposition-based interpolation from #interp_m3_m3m3.
*
- * @return R the interpolated matrix.
- * @param A the intput matrix which is totally effective with \a t = 0.0.
- * @param B the intput matrix which is totally effective with \a t = 1.0.
- * @param t the interpolation factor.
+ * \param R: Resulting interpolated matrix.
+ * \param A: Input matrix which is totally effective with `t = 0.0`.
+ * \param B: Input matrix which is totally effective with `t = 1.0`.
+ * \param t: Interpolation factor.
*/
void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t)
{
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index b285a74b8ac..23bd5e60e22 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -84,8 +84,6 @@ void mul_qt_qtqt(float q[4], const float q1[4], const float q2[4])
* \note:
* Assumes a unit quaternion?
*
- * \note: multiplying by 3x3 matrix is ~25% faster.
- *
* in fact not, but you may want to use a unit quat, read on...
*
* Shortcut for 'q v q*' when \a v is actually a quaternion.
@@ -98,6 +96,8 @@ void mul_qt_qtqt(float q[4], const float q1[4], const float q2[4])
*
* For people used to python mathutils, its like:
* def mul_qt_v3(q, v): (q * Quaternion((0.0, v[0], v[1], v[2])) * q.conjugated())[1:]
+ *
+ * \note: multiplying by 3x3 matrix is ~25% faster.
*/
void mul_qt_v3(const float q[4], float v[3])
{
@@ -1009,6 +1009,13 @@ void mat4_to_axis_angle(float axis[3], float *angle, float mat[4][4])
quat_to_axis_angle(axis, angle, q);
}
+void axis_angle_to_mat4_single(float mat[4][4], const char axis, const float angle)
+{
+ float mat3[3][3];
+ axis_angle_to_mat3_single(mat3, axis, angle);
+ copy_m4_m3(mat, mat3);
+}
+
/* rotation matrix from a single axis */
void axis_angle_to_mat3_single(float mat[3][3], const char axis, const float angle)
{
@@ -2140,38 +2147,37 @@ BLI_INLINE int _axis_signed(const int axis)
return (axis < 3) ? axis : axis - 3;
}
-/*
+/**
* Each argument us an axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z']
* where the first 2 are a source and the second 2 are the target.
*/
-int mat3_from_axis_conversion(int from_forward, int from_up, int to_forward, int to_up,
- float r_mat[3][3])
+bool mat3_from_axis_conversion(
+ int src_forward, int src_up, int dst_forward, int dst_up,
+ float r_mat[3][3])
{
// from functools import reduce
int value;
- unsigned int i;
- if (from_forward == to_forward && from_up == to_up) {
+ if (src_forward == dst_forward && src_up == dst_up) {
unit_m3(r_mat);
return false;
}
- if ((_axis_signed(from_forward) == _axis_signed(from_up)) ||
- (_axis_signed(to_forward) == _axis_signed(to_up)))
+ if ((_axis_signed(src_forward) == _axis_signed(src_up)) ||
+ (_axis_signed(dst_forward) == _axis_signed(dst_up)))
{
/* we could assert here! */
unit_m3(r_mat);
return false;
}
- value = ((from_forward << (0 * 3)) |
- (from_up << (1 * 3)) |
- (to_forward << (2 * 3)) |
- (to_up << (3 * 3)));
+ value = ((src_forward << (0 * 3)) |
+ (src_up << (1 * 3)) |
+ (dst_forward << (2 * 3)) |
+ (dst_up << (3 * 3)));
- for (i = 0; i < (sizeof(_axis_convert_matrix) / sizeof(*_axis_convert_matrix)); i++) {
- unsigned int j;
- for (j = 0; j < (sizeof(*_axis_convert_lut) / sizeof(*_axis_convert_lut[0])); j++) {
+ for (uint i = 0; i < (sizeof(_axis_convert_matrix) / sizeof(*_axis_convert_matrix)); i++) {
+ for (uint j = 0; j < (sizeof(*_axis_convert_lut) / sizeof(*_axis_convert_lut[0])); j++) {
if (_axis_convert_lut[i][j] == value) {
copy_m3_m3(r_mat, _axis_convert_matrix[i]);
return true;
@@ -2182,3 +2188,27 @@ int mat3_from_axis_conversion(int from_forward, int from_up, int to_forward, int
// BLI_assert(0);
return false;
}
+
+/**
+ * Use when the second axis can be guessed.
+ */
+bool mat3_from_axis_conversion_single(
+ int src_axis, int dst_axis,
+ float r_mat[3][3])
+{
+ if (src_axis == dst_axis) {
+ unit_m3(r_mat);
+ return false;
+ }
+
+ /* Pick predictable next axis. */
+ int src_axis_next = (src_axis + 1) % 3;
+ int dst_axis_next = (dst_axis + 1) % 3;
+
+ if ((src_axis < 3) != (dst_axis < 3)) {
+ /* Flip both axis so matrix sign remains positive. */
+ dst_axis_next += 3;
+ }
+
+ return mat3_from_axis_conversion(src_axis, src_axis_next, dst_axis, dst_axis_next, r_mat);
+}
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 95d5c9fde87..5f44c93e169 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -280,6 +280,16 @@ void mid_v3_v3v3v3v3(float v[3], const float v1[3], const float v2[3], const flo
v[2] = (v1[2] + v2[2] + v3[2] + v4[2]) / 4.0f;
}
+void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr)
+{
+ const float factor = 1.0f / (float)nbr;
+ zero_v3(r);
+
+ for (unsigned int i = 0; i < nbr; i++) {
+ madd_v3_v3fl(r, vec_arr[i], factor);
+ }
+}
+
/**
* Specialized function for calculating normals.
* fastpath for:
@@ -508,38 +518,27 @@ float angle_normalized_v2v2(const float v1[2], const float v2[2])
}
/**
- * angle between 2 vectors defined by 3 coords, about an axis. */
-float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3])
+ * Angle between 2 vectors, about an axis (axis can be considered a plane).
+ */
+float angle_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3])
{
- float v1_proj[3], v2_proj[3], tproj[3];
-
- sub_v3_v3v3(v1_proj, v1, v2);
- sub_v3_v3v3(v2_proj, v3, v2);
+ float v1_proj[3], v2_proj[3];
/* project the vectors onto the axis */
- project_v3_v3v3(tproj, v1_proj, axis);
- sub_v3_v3(v1_proj, tproj);
-
- project_v3_v3v3(tproj, v2_proj, axis);
- sub_v3_v3(v2_proj, tproj);
+ project_plane_normalized_v3_v3v3(v1_proj, v1, axis);
+ project_plane_normalized_v3_v3v3(v2_proj, v2, axis);
return angle_v3v3(v1_proj, v2_proj);
}
-float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3])
+float angle_signed_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3])
{
float v1_proj[3], v2_proj[3], tproj[3];
float angle;
- sub_v3_v3v3(v1_proj, v1, v2);
- sub_v3_v3v3(v2_proj, v3, v2);
-
/* project the vectors onto the axis */
- project_v3_v3v3(tproj, v1_proj, axis);
- sub_v3_v3(v1_proj, tproj);
-
- project_v3_v3v3(tproj, v2_proj, axis);
- sub_v3_v3(v2_proj, tproj);
+ project_plane_normalized_v3_v3v3(v1_proj, v1, axis);
+ project_plane_normalized_v3_v3v3(v2_proj, v2, axis);
angle = angle_v3v3(v1_proj, v2_proj);
@@ -552,6 +551,29 @@ float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const
return angle;
}
+/**
+ * Angle between 2 vectors defined by 3 coords, about an axis (axis can be considered a plane).
+ */
+float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3])
+{
+ float vec1[3], vec2[3];
+
+ sub_v3_v3v3(vec1, v1, v2);
+ sub_v3_v3v3(vec2, v3, v2);
+
+ return angle_on_axis_v3v3_v3(vec1, vec2, axis);
+}
+
+float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3])
+{
+ float vec1[3], vec2[3];
+
+ sub_v3_v3v3(vec1, v1, v2);
+ sub_v3_v3v3(vec2, v3, v2);
+
+ return angle_signed_on_axis_v3v3_v3(vec1, vec2, axis);
+}
+
void angle_tri_v3(float angles[3], const float v1[3], const float v2[3], const float v3[3])
{
float ed1[3], ed2[3], ed3[3];
@@ -630,6 +652,31 @@ void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
}
/**
+ * Project \a p onto a unit length \a v_proj
+ */
+void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2])
+{
+ BLI_ASSERT_UNIT_V2(v_proj);
+ const float mul = dot_v2v2(p, v_proj);
+
+ out[0] = mul * v_proj[0];
+ out[1] = mul * v_proj[1];
+}
+
+/**
+ * Project \a p onto a unit length \a v_proj
+ */
+void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3])
+{
+ BLI_ASSERT_UNIT_V3(v_proj);
+ const float mul = dot_v3v3(p, v_proj);
+
+ out[0] = mul * v_proj[0];
+ out[1] = mul * v_proj[1];
+ out[2] = mul * v_proj[2];
+}
+
+/**
* In this case plane is a 3D vector only (no 4th component).
*
* Projecting will make \a c a copy of \a v orthogonal to \a v_plane.
@@ -659,6 +706,25 @@ void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2
out[1] = p[1] - (mul * v_plane[1]);
}
+void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
+{
+ BLI_ASSERT_UNIT_V3(v_plane);
+ const float mul = dot_v3v3(p, v_plane);
+
+ 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_normalized_v2_v2v2(float out[2], const float p[2], const float v_plane[2])
+{
+ BLI_ASSERT_UNIT_V2(v_plane);
+ const float mul = dot_v2v2(p, v_plane);
+
+ 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 out[3], const float plane_no[3], const float plane_co[3])
{
@@ -687,7 +753,19 @@ 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)
+ * reflect = vec - ((2 * dot(vec, mirror)) * mirror).
+ *
+ * <pre>
+ * v
+ * + ^
+ * \ |
+ * \|
+ * + normal: axis of reflection
+ * /
+ * /
+ * +
+ * out: result (negate for a 'bounce').
+ * </pre>
*/
void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3])
{
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index e9fb77f6302..ee5e8651bd3 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -479,7 +479,18 @@ MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2])
r[1] = mat[1] * vec[0] + (+mat[0]) * vec[1];
}
-/* note: could add a matrix inline */
+/**
+ * Convenience function to get the projected depth of a position.
+ * This avoids creating a temporary 4D vector and multiplying it - only for the 4th component.
+ *
+ * Matches logic for:
+ *
+ * \code{.c}
+ * float co_4d[4] = {co[0], co[1], co[2], 1.0};
+ * mul_m4_v4(mat, co_4d);
+ * return co_4d[3];
+ * \endcode
+ */
MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3])
{
return (mat[0][3] * co[0]) +
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index f834c5b4c74..83012694ac0 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -1394,6 +1394,11 @@ static float voronoi_CrS(float x, float y, float z)
/* returns unsigned cellnoise */
static float cellNoiseU(float x, float y, float z)
{
+ /* avoid precision issues on unit coordinates */
+ x = (x + 0.000001f) * 1.00001f;
+ y = (y + 0.000001f) * 1.00001f;
+ z = (z + 0.000001f) * 1.00001f;
+
int xi = (int)(floor(x));
int yi = (int)(floor(y));
int zi = (int)(floor(z));
@@ -1411,6 +1416,11 @@ float cellNoise(float x, float y, float z)
/* returns a vector/point/color in ca, using point hasharray directly */
void cellNoiseV(float x, float y, float z, float ca[3])
{
+ /* avoid precision issues on unit coordinates */
+ x = (x + 0.000001f) * 1.00001f;
+ y = (y + 0.000001f) * 1.00001f;
+ z = (z + 0.000001f) * 1.00001f;
+
int xi = (int)(floor(x));
int yi = (int)(floor(y));
int zi = (int)(floor(z));
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index f0d0bd00dea..4b3a74d02ae 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -63,9 +63,6 @@
#include "MEM_guardedalloc.h"
-/* local */
-#define UNIQUE_NAME_MAX 128
-
/* Declarations */
#ifdef WIN32
@@ -147,162 +144,6 @@ void BLI_stringenc(char *string, const char *head, const char *tail, unsigned sh
sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
}
-/**
- * Looks for a numeric suffix preceded by delim character on the end of
- * name, puts preceding part into *left and value of suffix into *nr.
- * Returns the length of *left.
- *
- * Foo.001 -> "Foo", 1
- * Returning the length of "Foo"
- *
- * \param left Where to return copy of part preceding delim
- * \param nr Where to return value of numeric suffix
- * \param name String to split
- * \param delim Delimiter character
- * \return Length of \a left
- */
-int BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
-{
- const int name_len = strlen(name);
-
- *nr = 0;
- memcpy(left, name, (name_len + 1) * sizeof(char));
-
- /* name doesn't end with a delimiter "foo." */
- if ((name_len > 1 && name[name_len - 1] == delim) == 0) {
- int a = name_len;
- while (a--) {
- if (name[a] == delim) {
- left[a] = '\0'; /* truncate left part here */
- *nr = atol(name + a + 1);
- /* casting down to an int, can overflow for large numbers */
- if (*nr < 0)
- *nr = 0;
- return a;
- }
- else if (isdigit(name[a]) == 0) {
- /* non-numeric suffix - give up */
- break;
- }
- }
- }
-
- return name_len;
-}
-
-/**
- * Ensures name is unique (according to criteria specified by caller in unique_check callback),
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param unique_check Return true if name is not unique
- * \param arg Additional arg to unique_check--meaning is up to caller
- * \param defname To initialize name if latter is empty
- * \param delim Delimits numeric suffix in name
- * \param name Name to be ensured unique
- * \param name_len Maximum length of name area
- * \return true if there if the name was changed
- */
-bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name),
- void *arg, const char *defname, char delim, char *name, int name_len)
-{
- if (name[0] == '\0') {
- BLI_strncpy(name, defname, name_len);
- }
-
- if (unique_check(arg, name)) {
- char numstr[16];
- char tempname[UNIQUE_NAME_MAX];
- char left[UNIQUE_NAME_MAX];
- int number;
- int len = BLI_split_name_num(left, &number, name, delim);
- do {
- /* add 1 to account for \0 */
- const int numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1;
-
- /* highly unlikely the string only has enough room for the number
- * but support anyway */
- if ((len == 0) || (numlen >= name_len)) {
- /* number is know not to be utf-8 */
- BLI_strncpy(tempname, numstr, name_len);
- }
- else {
- char *tempname_buf;
- tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen);
- memcpy(tempname_buf, numstr, numlen);
- }
- } while (unique_check(arg, tempname));
-
- BLI_strncpy(name, tempname, name_len);
-
- return true;
- }
-
- return false;
-}
-
-/* little helper macro for BLI_uniquename */
-#ifndef GIVE_STRADDR
-# define GIVE_STRADDR(data, offset) ( ((char *)data) + offset)
-#endif
-
-/* Generic function to set a unique name. It is only designed to be used in situations
- * where the name is part of the struct, and also that the name is at most UNIQUE_NAME_MAX chars long.
- *
- * For places where this is used, see constraint.c for example...
- *
- * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
- * len: maximum length of string (to prevent overflows, etc.)
- * defname: the name that should be used by default if none is specified already
- * delim: the character which acts as a delimiter between parts of the name
- */
-static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
-{
- Link *link;
-
- for (link = list->first; link; link = link->next) {
- if (link != vlink) {
- if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static bool uniquename_unique_check(void *arg, const char *name)
-{
- struct {ListBase *lb; void *vlink; int name_offs; } *data = arg;
- return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
-}
-
-/**
- * Ensures that the specified block has a unique name within the containing list,
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param list List containing the block
- * \param vlink The block to check the name for
- * \param defname To initialize block name if latter is empty
- * \param delim Delimits numeric suffix in name
- * \param name_offs Offset of name within block structure
- * \param name_len Maximum length of name area
- */
-bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim, int name_offs, int name_len)
-{
- struct {ListBase *lb; void *vlink; int name_offs; } data;
- data.lb = list;
- data.vlink = vlink;
- data.name_offs = name_offs;
-
- assert((name_len > 1) && (name_len <= UNIQUE_NAME_MAX));
-
- /* See if we are given an empty string */
- if (ELEM(NULL, vlink, defname))
- return false;
-
- return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
-}
-
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
/* ******************** string encoding ***************** */
@@ -1326,52 +1167,16 @@ bool BLI_path_program_search(
}
/**
- * Copies into *last the part of *dir following the second-last slash.
- */
-void BLI_getlastdir(const char *dir, char *last, const size_t maxlen)
-{
- const char *s = dir;
- const char *lslash = NULL;
- const char *prevslash = NULL;
- while (*s) {
- if ((*s == '\\') || (*s == '/')) {
- prevslash = lslash;
- lslash = s;
- }
- s++;
- }
- if (prevslash) {
- BLI_strncpy(last, prevslash + 1, maxlen);
- }
- else {
- BLI_strncpy(last, dir, maxlen);
- }
-}
-
-
-/**
* Sets the specified environment variable to the specified value,
* and clears it if val == NULL.
*/
void BLI_setenv(const char *env, const char *val)
{
/* free windows */
-#if (defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)
- char *envstr;
- if (val)
- envstr = BLI_sprintfN("%s=%s", env, val);
- else
- envstr = BLI_sprintfN("%s=", env);
-
- putenv(envstr);
- MEM_freeN(envstr);
-
- /* non-free windows */
-#elif (defined(WIN32) || defined(WIN64)) /* not free windows */
+#if (defined(WIN32) || defined(WIN64))
uputenv(env, val);
-
#else
/* linux/osx/bsd */
if (val)
@@ -1417,14 +1222,16 @@ void BLI_make_exist(char *dir)
/**
* Ensures that the parent directory of *name exists.
+ *
+ * \return true on success (i.e. given path now exists on FS), false otherwise.
*/
-void BLI_make_existing_file(const char *name)
+bool BLI_make_existing_file(const char *name)
{
char di[FILE_MAX];
BLI_split_dir_part(name, di, sizeof(di));
/* make if the dir doesn't exist */
- BLI_dir_create_recursive(di);
+ return BLI_dir_create_recursive(di);
}
/**
@@ -1774,6 +1581,90 @@ void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__r
}
/**
+ * Join multiple strings into a path, ensuring only a single path separator between each,
+ * and trailing slash is kept.
+ *
+ * \note If you want a trailing slash, add ``SEP_STR`` as the last path argument,
+ * duplicate slashes will be cleaned up.
+ */
+size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...)
+{
+ if (UNLIKELY(dst_len == 0)) {
+ return 0;
+ }
+ const size_t dst_last = dst_len - 1;
+ size_t ofs = BLI_strncpy_rlen(dst, path, dst_len);
+
+ if (ofs == dst_last) {
+ return ofs;
+ }
+
+ /* remove trailing slashes, unless there are _only_ trailing slashes
+ * (allow "//" as the first argument). */
+ bool has_trailing_slash = false;
+ if (ofs != 0) {
+ size_t len = ofs;
+ while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) {
+ len -= 1;
+ }
+ if (len != 0) {
+ ofs = len;
+ }
+ has_trailing_slash = (path[len] != '\0');
+ }
+
+ va_list args;
+ va_start(args, path);
+ while ((path = (const char *) va_arg(args, const char *))) {
+ has_trailing_slash = false;
+ const char *path_init = path;
+ while (ELEM(path[0], SEP, ALTSEP)) {
+ path++;
+ }
+ size_t len = strlen(path);
+ if (len != 0) {
+ while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) {
+ len -= 1;
+ }
+
+ if (len != 0) {
+ /* the very first path may have a slash at the end */
+ if (ofs && !ELEM(dst[ofs - 1], SEP, ALTSEP)) {
+ dst[ofs++] = SEP;
+ if (ofs == dst_last) {
+ break;
+ }
+ }
+ has_trailing_slash = (path[len] != '\0');
+ if (ofs + len >= dst_last) {
+ len = dst_last - ofs;
+ }
+ memcpy(&dst[ofs], path, len);
+ ofs += len;
+ if (ofs == dst_last) {
+ break;
+ }
+ }
+ }
+ else {
+ has_trailing_slash = (path_init != path);
+ }
+ }
+ va_end(args);
+
+ if (has_trailing_slash) {
+ if ((ofs != dst_last) && (ofs != 0) && (ELEM(dst[ofs - 1], SEP, ALTSEP) == 0)) {
+ dst[ofs++] = SEP;
+ }
+ }
+
+ BLI_assert(ofs <= dst_last);
+ dst[ofs] = '\0';
+
+ return ofs;
+}
+
+/**
* like pythons os.path.basename()
*
* \return The pointer into \a path string immediately after last slash,
@@ -1785,6 +1676,71 @@ const char *BLI_path_basename(const char *path)
return filename ? filename + 1 : path;
}
+/**
+ * Get an element of the path at an index, eg:
+ * "/some/path/file.txt" where an index of...
+ * - 0 or -3: "some"
+ * - 1 or -2: "path"
+ * - 2 or -1: "file.txt"
+ *
+ * Ignores multiple slashes at any point in the path (including start/end).
+ */
+bool BLI_path_name_at_index(const char *path, const int index, int *r_offset, int *r_len)
+{
+ if (index >= 0) {
+ int index_step = 0;
+ int prev = -1;
+ int i = 0;
+ while (true) {
+ const char c = path[i];
+ if (ELEM(c, SEP, ALTSEP, '\0')) {
+ if (prev + 1 != i) {
+ prev += 1;
+ if (index_step == index) {
+ *r_offset = prev;
+ *r_len = i - prev;
+ /* printf("!!! %d %d\n", start, end); */
+ return true;
+ }
+ index_step += 1;
+ }
+ if (c == '\0') {
+ break;
+ }
+ prev = i;
+ }
+ i += 1;
+ }
+ return false;
+ }
+ else {
+ /* negative number, reverse where -1 is the last element */
+ int index_step = -1;
+ int prev = strlen(path);
+ int i = prev - 1;
+ while (true) {
+ const char c = i >= 0 ? path[i] : '\0';
+ if (ELEM(c, SEP, ALTSEP, '\0')) {
+ if (prev - 1 != i) {
+ i += 1;
+ if (index_step == index) {
+ *r_offset = i;
+ *r_len = prev - i;
+ return true;
+ }
+ index_step -= 1;
+ }
+ if (c == '\0') {
+ break;
+ }
+ prev = i;
+ }
+ i -= 1;
+ }
+ return false;
+ }
+}
+
/* UNUSED */
#if 0
/**
diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c
index 8d9881e4539..018e2f9be5a 100644
--- a/source/blender/blenlib/intern/polyfill2d.c
+++ b/source/blender/blenlib/intern/polyfill2d.c
@@ -21,8 +21,15 @@
/** \file blender/blenlib/intern/polyfill2d.c
* \ingroup bli
*
- * A simple implementation of the ear cutting algorithm
- * to triangulate simple polygons without holes.
+ * An ear clipping algorithm to triangulate single boundary polygons.
+ *
+ * Details:
+ *
+ * - The algorithm guarantees all triangles are assigned (number of coords - 2)
+ * and that triangles will have non-overlapping indices (even for degenerate geometry).
+ * - Self-intersections are considered degenerate (resulting triangles will overlap).
+ * - While multiple polygons aren't supported, holes can still be defined using *key-holes*
+ * (where the polygon doubles back on its self with *exactly* matching coordinates).
*
* \note
*
@@ -74,6 +81,12 @@ typedef signed char eSign;
#ifdef USE_KDTREE
/**
+ * Spatial optimization for point-in-triangle intersection checks.
+ * The simple version of this algorithm is ``O(n^2)`` complexity
+ * (every point needing to check the triangle defined by every other point),
+ * Using a binary-tree reduces the complexity to ``O(n log n)``
+ * plus some overhead of creating the tree.
+ *
* This is a single purpose KDTree based on BLI_kdtree with some modifications
* to better suit polyfill2d.
*
@@ -92,24 +105,24 @@ typedef bool axis_t;
/* use for sorting */
typedef struct KDTreeNode2D_head {
- unsigned int neg, pos;
- unsigned int index;
+ uint neg, pos;
+ uint index;
} KDTreeNode2D_head;
typedef struct KDTreeNode2D {
- unsigned int neg, pos;
- unsigned int index;
+ uint neg, pos;
+ uint index;
axis_t axis; /* range is only (0-1) */
- unsigned short flag;
- unsigned int parent;
+ ushort flag;
+ uint parent;
} KDTreeNode2D;
struct KDTree2D {
KDTreeNode2D *nodes;
const float (*coords)[2];
- unsigned int root;
- unsigned int totnode;
- unsigned int *nodes_map; /* index -> node lookup */
+ uint root;
+ uint totnode;
+ uint *nodes_map; /* index -> node lookup */
};
struct KDRange2D {
@@ -127,14 +140,14 @@ typedef struct PolyFill {
struct PolyIndex *indices; /* vertex aligned */
const float (*coords)[2];
- unsigned int coords_tot;
+ uint coords_tot;
#ifdef USE_CONVEX_SKIP
- unsigned int coords_tot_concave;
+ uint coords_tot_concave;
#endif
/* A polygon with n vertices has a triangulation of n-2 triangles. */
- unsigned int (*tris)[3];
- unsigned int tris_tot;
+ uint (*tris)[3];
+ uint tris_tot;
#ifdef USE_KDTREE
struct KDTree2D kdtree;
@@ -145,7 +158,7 @@ typedef struct PolyFill {
/* circular linklist */
typedef struct PolyIndex {
struct PolyIndex *next, *prev;
- unsigned int index;
+ uint index;
eSign sign;
} PolyIndex;
@@ -199,7 +212,7 @@ static eSign span_tri_v2_sign(const float v1[2], const float v2[2], const float
#ifdef USE_KDTREE
-#define KDNODE_UNSET ((unsigned int)-1)
+#define KDNODE_UNSET ((uint)-1)
enum {
KDNODE_FLAG_REMOVED = (1 << 0),
@@ -207,7 +220,7 @@ enum {
static void kdtree2d_new(
struct KDTree2D *tree,
- unsigned int tot,
+ uint tot,
const float (*coords)[2])
{
/* set by caller */
@@ -222,11 +235,11 @@ static void kdtree2d_new(
*/
static void kdtree2d_init(
struct KDTree2D *tree,
- const unsigned int coords_tot,
+ const uint coords_tot,
const PolyIndex *indices)
{
KDTreeNode2D *node;
- unsigned int i;
+ uint i;
for (i = 0, node = tree->nodes; i < coords_tot; i++) {
if (indices[i].sign != CONVEX) {
@@ -238,15 +251,15 @@ static void kdtree2d_init(
}
}
- BLI_assert(tree->totnode == (unsigned int)(node - tree->nodes));
+ BLI_assert(tree->totnode == (uint)(node - tree->nodes));
}
-static unsigned int kdtree2d_balance_recursive(
- KDTreeNode2D *nodes, unsigned int totnode, axis_t axis,
- const float (*coords)[2], const unsigned int ofs)
+static uint kdtree2d_balance_recursive(
+ KDTreeNode2D *nodes, uint totnode, axis_t axis,
+ const float (*coords)[2], const uint ofs)
{
KDTreeNode2D *node;
- unsigned int neg, pos, median, i, j;
+ uint neg, pos, median, i, j;
if (totnode <= 0) {
return KDNODE_UNSET;
@@ -304,7 +317,7 @@ static void kdtree2d_balance(
static void kdtree2d_init_mapping(
struct KDTree2D *tree)
{
- unsigned int i;
+ uint i;
KDTreeNode2D *node;
for (i = 0, node = tree->nodes; i < tree->totnode; i++, node++) {
@@ -325,9 +338,9 @@ static void kdtree2d_init_mapping(
static void kdtree2d_node_remove(
struct KDTree2D *tree,
- unsigned int index)
+ uint index)
{
- unsigned int node_index = tree->nodes_map[index];
+ uint node_index = tree->nodes_map[index];
KDTreeNode2D *node;
if (node_index == KDNODE_UNSET) {
@@ -349,7 +362,7 @@ static void kdtree2d_node_remove(
{
KDTreeNode2D *node_parent = &tree->nodes[node->parent];
- BLI_assert((unsigned int)(node - tree->nodes) == node_index);
+ BLI_assert((uint)(node - tree->nodes) == node_index);
if (node_parent->neg == node_index) {
node_parent->neg = KDNODE_UNSET;
}
@@ -370,7 +383,7 @@ static void kdtree2d_node_remove(
static bool kdtree2d_isect_tri_recursive(
const struct KDTree2D *tree,
- const unsigned int tri_index[3],
+ const uint tri_index[3],
const float *tri_coords[3],
const float tri_center[2],
const struct KDRange2D bounds[2],
@@ -398,11 +411,11 @@ static bool kdtree2d_isect_tri_recursive(
}
#define KDTREE2D_ISECT_TRI_RECURSE_NEG \
- (((node->neg != KDNODE_UNSET) && (co[node->axis] > bounds[node->axis].min)) && \
+ (((node->neg != KDNODE_UNSET) && (co[node->axis] >= bounds[node->axis].min)) && \
(kdtree2d_isect_tri_recursive(tree, tri_index, tri_coords, tri_center, bounds, \
&tree->nodes[node->neg])))
#define KDTREE2D_ISECT_TRI_RECURSE_POS \
- (((node->pos != KDNODE_UNSET) && (co[node->axis] < bounds[node->axis].max)) && \
+ (((node->pos != KDNODE_UNSET) && (co[node->axis] <= bounds[node->axis].max)) && \
(kdtree2d_isect_tri_recursive(tree, tri_index, tri_coords, tri_center, bounds, \
&tree->nodes[node->pos])))
@@ -433,10 +446,10 @@ static bool kdtree2d_isect_tri_recursive(
static bool kdtree2d_isect_tri(
struct KDTree2D *tree,
- const unsigned int ind[3])
+ const uint ind[3])
{
const float *vs[3];
- unsigned int i;
+ uint i;
struct KDRange2D bounds[2] = {
{FLT_MAX, -FLT_MAX},
{FLT_MAX, -FLT_MAX},
@@ -462,7 +475,7 @@ static bool kdtree2d_isect_tri(
#endif /* USE_KDTREE */
-static unsigned int *pf_tri_add(PolyFill *pf)
+static uint *pf_tri_add(PolyFill *pf)
{
return pf->tris[pf->tris_tot++];
}
@@ -483,7 +496,7 @@ static void pf_coord_remove(PolyFill *pf, PolyIndex *pi)
pf->indices = pi->next;
}
#ifdef DEBUG
- pi->index = (unsigned int)-1;
+ pi->index = (uint)-1;
pi->next = pi->prev = NULL;
#endif
@@ -581,7 +594,7 @@ static void pf_triangulate(PolyFill *pf)
}
if (pf->coords_tot == 3) {
- unsigned int *tri = pf_tri_add(pf);
+ uint *tri = pf_tri_add(pf);
pi_ear = pf->indices;
tri[0] = pi_ear->index; pi_ear = pi_ear->next;
tri[1] = pi_ear->index; pi_ear = pi_ear->next;
@@ -614,10 +627,10 @@ static PolyIndex *pf_ear_tip_find(
)
{
/* localize */
- const unsigned int coords_tot = pf->coords_tot;
+ const uint coords_tot = pf->coords_tot;
PolyIndex *pi_ear;
- unsigned int i;
+ uint i;
#ifdef USE_CLIP_EVEN
pi_ear = pi_ear_init;
@@ -675,7 +688,7 @@ static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip)
#endif
#if defined(USE_CONVEX_SKIP) && !defined(USE_KDTREE)
- unsigned int coords_tot_concave_checked = 0;
+ uint coords_tot_concave_checked = 0;
#endif
@@ -684,13 +697,13 @@ static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip)
#ifdef USE_CONVEX_SKIP_TEST
/* check if counting is wrong */
{
- unsigned int coords_tot_concave_test = 0;
- unsigned int i = pf->coords_tot;
- while (i--) {
- if (coords_sign[indices[i]] != CONVEX) {
+ uint coords_tot_concave_test = 0;
+ PolyIndex *pi_iter = pi_ear_tip;
+ do {
+ if (pi_iter->sign != CONVEX) {
coords_tot_concave_test += 1;
}
- }
+ } while ((pi_iter = pi_iter->next) != pi_ear_tip);
BLI_assert(coords_tot_concave_test == pf->coords_tot_concave);
}
#endif
@@ -707,7 +720,7 @@ static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip)
#ifdef USE_KDTREE
{
- const unsigned int ind[3] = {
+ const uint ind[3] = {
pi_ear_tip->index,
pi_ear_tip->next->index,
pi_ear_tip->prev->index};
@@ -758,7 +771,7 @@ static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip)
static void pf_ear_tip_cut(PolyFill *pf, PolyIndex *pi_ear_tip)
{
- unsigned int *tri = pf_tri_add(pf);
+ uint *tri = pf_tri_add(pf);
tri[0] = pi_ear_tip->prev->index;
tri[1] = pi_ear_tip->index;
@@ -773,15 +786,15 @@ static void pf_ear_tip_cut(PolyFill *pf, PolyIndex *pi_ear_tip)
static void polyfill_prepare(
PolyFill *pf,
const float (*coords)[2],
- const unsigned int coords_tot,
+ const uint coords_tot,
int coords_sign,
- unsigned int (*r_tris)[3],
+ uint (*r_tris)[3],
PolyIndex *r_indices)
{
/* localize */
PolyIndex *indices = r_indices;
- unsigned int i;
+ uint i;
/* assign all polyfill members here */
pf->indices = r_indices;
@@ -819,7 +832,7 @@ static void polyfill_prepare(
}
else {
/* reversed */
- unsigned int n = coords_tot - 1;
+ uint n = coords_tot - 1;
for (i = 0; i < coords_tot; i++) {
indices[i].next = &indices[i + 1];
indices[i].prev = &indices[i - 1];
@@ -863,9 +876,9 @@ static void polyfill_calc(
*/
void BLI_polyfill_calc_arena(
const float (*coords)[2],
- const unsigned int coords_tot,
+ const uint coords_tot,
const int coords_sign,
- unsigned int (*r_tris)[3],
+ uint (*r_tris)[3],
struct MemArena *arena)
{
@@ -919,9 +932,9 @@ void BLI_polyfill_calc_arena(
*/
void BLI_polyfill_calc(
const float (*coords)[2],
- const unsigned int coords_tot,
+ const uint coords_tot,
const int coords_sign,
- unsigned int (*r_tris)[3])
+ uint (*r_tris)[3])
{
PolyFill pf;
PolyIndex *indices = BLI_array_alloca(indices, coords_tot);
diff --git a/source/blender/blenlib/intern/polyfill2d_beautify.c b/source/blender/blenlib/intern/polyfill2d_beautify.c
index 896177f436c..5f6fb8e6cd4 100644
--- a/source/blender/blenlib/intern/polyfill2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill2d_beautify.c
@@ -121,45 +121,53 @@ BLI_INLINE bool is_boundary_edge(unsigned int i_a, unsigned int i_b, const unsig
* Assuming we have 2 triangles sharing an edge (2 - 4),
* check if the edge running from (1 - 3) gives better results.
*
+ * \param lock_degenerate: Use to avoid rotating out of a degenerate state.
+ * - When true, an existing zero area face on either side of the (2 - 4) split will return a positive value.
+ * - When false, the check must be non-biased towards either split direction.
+ *
* \return (negative number means the edge can be rotated, lager == better).
*/
-float BLI_polyfill_beautify_quad_rotate_calc(
- const float v1[2], const float v2[2], const float v3[2], const float v4[2])
+float BLI_polyfill_beautify_quad_rotate_calc_ex(
+ const float v1[2], const float v2[2], const float v3[2], const float v4[2],
+ const bool lock_degenerate)
{
/* not a loop (only to be able to break out) */
do {
- bool is_zero_a, is_zero_b;
-
+ /* Allow very small faces to be considered non-zero. */
+ const float eps_zero_area = 1e-12f;
const float area_2x_234 = cross_tri_v2(v2, v3, v4);
const float area_2x_241 = cross_tri_v2(v2, v4, v1);
const float area_2x_123 = cross_tri_v2(v1, v2, v3);
const float area_2x_134 = cross_tri_v2(v1, v3, v4);
- {
- BLI_assert((ELEM(v1, v2, v3, v4) == false) &&
- (ELEM(v2, v1, v3, v4) == false) &&
- (ELEM(v3, v1, v2, v4) == false) &&
- (ELEM(v4, v1, v2, v3) == false));
-
- is_zero_a = (fabsf(area_2x_234) <= FLT_EPSILON);
- is_zero_b = (fabsf(area_2x_241) <= FLT_EPSILON);
-
- if (is_zero_a && is_zero_b) {
- break;
- }
+ BLI_assert((ELEM(v1, v2, v3, v4) == false) &&
+ (ELEM(v2, v1, v3, v4) == false) &&
+ (ELEM(v3, v1, v2, v4) == false) &&
+ (ELEM(v4, v1, v2, v3) == false));
+ /*
+ * Test for unusable (1-3) state.
+ * - Area sign flipping to check faces aren't going to point in opposite directions.
+ * - Area epsilon check that the one of the faces won't be zero area.
+ */
+ if ((area_2x_123 >= 0.0f) != (area_2x_134 >= 0.0f)) {
+ break;
}
-
- /* one of the tri's was degenerate, check we're not rotating
- * into a different degenerate shape or flipping the face */
- if ((fabsf(area_2x_123) <= FLT_EPSILON) || (fabsf(area_2x_134) <= FLT_EPSILON)) {
- /* one of the new rotations is degenerate */
+ else if ((fabsf(area_2x_123) <= eps_zero_area) || (fabsf(area_2x_134) <= eps_zero_area)) {
break;
}
- if ((area_2x_123 >= 0.0f) != (area_2x_134 >= 0.0f)) {
- /* rotation would cause flipping */
- break;
+ /* Test for unusable (2-4) state (same as above). */
+ if ((area_2x_234 >= 0.0f) != (area_2x_241 >= 0.0f)) {
+ if (lock_degenerate) {
+ break;
+ }
+ else {
+ return -FLT_MAX; /* always rotate */
+ }
+ }
+ else if ((fabsf(area_2x_234) <= eps_zero_area) || (fabsf(area_2x_241) <= eps_zero_area)) {
+ return -FLT_MAX; /* always rotate */
}
{
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 9d5a4630f68..3adc6b30f6e 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -32,6 +32,7 @@
* A minimalist lib for functions doing stuff with rectangle structs.
*/
+#include <stdlib.h>
#include <stdio.h>
#include <math.h>
@@ -41,6 +42,9 @@
#include "DNA_vec_types.h"
#include "BLI_rect.h"
+/* avoid including BLI_math */
+static void unit_m4(float m[4][4]);
+
/**
* Determine if a rect is empty. An empty
* rect is one with a zero (or negative)
@@ -351,6 +355,22 @@ void BLI_rcti_init(rcti *rect, int xmin, int xmax, int ymin, int ymax)
}
}
+void BLI_rctf_init_pt_radius(rctf *rect, const float xy[2], float size)
+{
+ rect->xmin = xy[0] - size;
+ rect->xmax = xy[0] + size;
+ rect->ymin = xy[1] - size;
+ rect->ymax = xy[1] + size;
+}
+
+void BLI_rcti_init_pt_radius(rcti *rect, const int xy[2], int size)
+{
+ rect->xmin = xy[0] - size;
+ rect->xmax = xy[0] + size;
+ rect->ymin = xy[1] - size;
+ rect->ymax = xy[1] + size;
+}
+
void BLI_rcti_init_minmax(rcti *rect)
{
rect->xmin = rect->ymin = INT_MAX;
@@ -389,6 +409,31 @@ void BLI_rctf_transform_pt_v(const rctf *dst, const rctf *src, float xy_dst[2],
xy_dst[1] = dst->ymin + ((dst->ymax - dst->ymin) * xy_dst[1]);
}
+/**
+ * Calculate a 4x4 matrix representing the transformation between two rectangles.
+ *
+ * \note Multiplying a vector by this matrix does *not* give the same value as #BLI_rctf_transform_pt_v.
+ */
+void BLI_rctf_transform_calc_m4_pivot_min_ex(
+ const rctf *dst, const rctf *src, float matrix[4][4],
+ uint x, uint y)
+{
+ BLI_assert(x < 3 && y < 3);
+
+ unit_m4(matrix);
+
+ matrix[x][x] = BLI_rctf_size_x(src) / BLI_rctf_size_x(dst);
+ matrix[y][y] = BLI_rctf_size_y(src) / BLI_rctf_size_y(dst);
+ matrix[3][x] = (src->xmin - dst->xmin) * matrix[x][x];
+ matrix[3][y] = (src->ymin - dst->ymin) * matrix[y][y];
+}
+
+void BLI_rctf_transform_calc_m4_pivot_min(
+ const rctf *dst, const rctf *src, float matrix[4][4])
+{
+ BLI_rctf_transform_calc_m4_pivot_min_ex(dst, src, matrix, 0, 1);
+}
+
void BLI_rcti_translate(rcti *rect, int x, int y)
{
rect->xmin += x;
@@ -420,20 +465,16 @@ void BLI_rctf_recenter(rctf *rect, float x, float y)
/* change width & height around the central location */
void BLI_rcti_resize(rcti *rect, int x, int y)
{
- rect->xmin = rect->xmax = BLI_rcti_cent_x(rect);
- rect->ymin = rect->ymax = BLI_rcti_cent_y(rect);
- rect->xmin -= x / 2;
- rect->ymin -= y / 2;
+ rect->xmin = BLI_rcti_cent_x(rect) - (x / 2);
+ rect->ymin = BLI_rcti_cent_y(rect) - (y / 2);
rect->xmax = rect->xmin + x;
rect->ymax = rect->ymin + y;
}
void BLI_rctf_resize(rctf *rect, float x, float y)
{
- rect->xmin = rect->xmax = BLI_rctf_cent_x(rect);
- rect->ymin = rect->ymax = BLI_rctf_cent_y(rect);
- rect->xmin -= x * 0.5f;
- rect->ymin -= y * 0.5f;
+ rect->xmin = BLI_rctf_cent_x(rect) - (x * 0.5f);
+ rect->ymin = BLI_rctf_cent_y(rect) - (y * 0.5f);
rect->xmax = rect->xmin + x;
rect->ymax = rect->ymin + y;
}
@@ -681,6 +722,14 @@ void BLI_rcti_rctf_copy_floor(rcti *dst, const rctf *src)
dst->ymax = floorf(src->ymax);
}
+void BLI_rcti_rctf_copy_round(rcti *dst, const rctf *src)
+{
+ dst->xmin = floorf(src->xmin + 0.5f);
+ dst->xmax = floorf(src->xmax + 0.5f);
+ dst->ymin = floorf(src->ymin + 0.5f);
+ dst->ymax = floorf(src->ymax + 0.5f);
+}
+
void BLI_rctf_rcti_copy(rctf *dst, const rcti *src)
{
dst->xmin = src->xmin;
@@ -743,3 +792,12 @@ void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle)
#undef ROTATE_SINCOS
/** \} */
+
+static void unit_m4(float m[4][4])
+{
+ m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f;
+ m[0][1] = m[0][2] = m[0][3] = 0.0f;
+ m[1][0] = m[1][2] = m[1][3] = 0.0f;
+ m[2][0] = m[2][1] = m[2][3] = 0.0f;
+ m[3][0] = m[3][1] = m[3][2] = 0.0f;
+}
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 3edc00a8c1a..a48c8b074dd 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -37,14 +37,10 @@
#include <sys/stat.h>
-#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || defined(__sun)
+#if defined(__NetBSD__) || defined(__DragonFly__)
/* Other modern unix os's should probably use this also */
# include <sys/statvfs.h>
# define USE_STATFS_STATVFS
-#elif (defined(__sparc) || defined(__sparc__)) && !defined(__FreeBSD__) && !defined(__linux__)
-# include <sys/statfs.h>
- /* 4 argument version (not common) */
-# define USE_STATFS_4ARGS
#endif
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
@@ -113,7 +109,7 @@ double BLI_dir_free_space(const char *dir)
#ifdef WIN32
DWORD sectorspc, bytesps, freec, clusters;
char tmp[4];
-
+
tmp[0] = '\\'; tmp[1] = 0; /* Just a failsafe */
if (dir[0] == '/' || dir[0] == '\\') {
tmp[0] = '\\';
@@ -139,10 +135,10 @@ double BLI_dir_free_space(const char *dir)
char name[FILE_MAXDIR], *slash;
int len = strlen(dir);
-
+
if (len >= FILE_MAXDIR) /* path too long */
return -1;
-
+
strcpy(name, dir);
if (len) {
@@ -194,7 +190,7 @@ size_t BLI_file_size(const char *path)
*/
int BLI_exists(const char *name)
{
-#if defined(WIN32)
+#if defined(WIN32)
BLI_stat_t st;
wchar_t *tmp_16 = alloc_utf16_from_8(name, 1);
int len, res;
@@ -253,10 +249,8 @@ int BLI_stat(const char *path, BLI_stat_t *buffer)
int BLI_wstat(const wchar_t *path, BLI_stat_t *buffer)
{
-#if defined(_MSC_VER) || defined(__MINGW64__)
+#if defined(_MSC_VER)
return _wstat64(path, buffer);
-#elif defined(__MINGW32__)
- return _wstati64(path, buffer);
#else
return _wstat(path, buffer);
#endif
@@ -372,7 +366,7 @@ LinkNode *BLI_file_read_as_lines(const char *name)
size_t size;
if (!fp) return NULL;
-
+
fseek(fp, 0, SEEK_END);
size = (size_t)ftell(fp);
fseek(fp, 0, SEEK_SET);
@@ -385,7 +379,7 @@ LinkNode *BLI_file_read_as_lines(const char *name)
buf = MEM_mallocN(size, "file_as_lines");
if (buf) {
size_t i, last = 0;
-
+
/*
* size = because on win32 reading
* all the bytes in the file will return
@@ -403,10 +397,10 @@ LinkNode *BLI_file_read_as_lines(const char *name)
last = i + 1;
}
}
-
+
MEM_freeN(buf);
}
-
+
fclose(fp);
return lines.list;
@@ -424,23 +418,13 @@ void BLI_file_free_lines(LinkNode *lines)
bool BLI_file_older(const char *file1, const char *file2)
{
#ifdef WIN32
-#ifndef __MINGW32__
struct _stat st1, st2;
-#else
- struct _stati64 st1, st2;
-#endif
UTF16_ENCODE(file1);
UTF16_ENCODE(file2);
-
-#ifndef __MINGW32__
+
if (_wstat(file1_16, &st1)) return false;
if (_wstat(file2_16, &st2)) return false;
-#else
- if (_wstati64(file1_16, &st1)) return false;
- if (_wstati64(file2_16, &st2)) return false;
-#endif
-
UTF16_UN_ENCODE(file2);
UTF16_UN_ENCODE(file1);
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index f62ffe9e985..6022732025b 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -332,7 +332,7 @@ size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const siz
goto escape_finish;
case '\\':
case '"':
- /* fall-through */
+ ATTR_FALLTHROUGH;
/* less common but should also be support */
case '\t':
@@ -346,7 +346,7 @@ size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const siz
/* not enough space to escape */
break;
}
- /* fall-through */
+ ATTR_FALLTHROUGH;
default:
*dst = *src;
break;
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 96033615cf5..229a97a2fa7 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -47,6 +47,19 @@
// #define DEBUG_STRSIZE
+/* array copied from glib's gutf8.c, */
+/* Note: last two values (0xfe and 0xff) are forbidden in utf-8, so they are considered 1 byte length too. */
+static const size_t utf8_skip_data[256] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
+};
+
/* from libswish3, originally called u8_isvalid(),
* modified to return the index of the bad character (byte index not utf).
* http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */
@@ -56,73 +69,91 @@
* length is in bytes, since without knowing whether the string is valid
* it's hard to know how many characters there are! */
-static const char trailingBytesForUTF8[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
-};
-
-int BLI_utf8_invalid_byte(const char *str, int length)
+/**
+ * Find first utf-8 invalid byte in given \a str, of \a length bytes.
+ *
+ * \return the offset of the first invalid byte.
+ */
+ptrdiff_t BLI_utf8_invalid_byte(const char *str, size_t length)
{
- const unsigned char *p, *pend = (const unsigned char *)str + length;
+ const unsigned char *p, *perr, *pend = (const unsigned char *)str + length;
unsigned char c;
int ab;
- for (p = (const unsigned char *)str; p < pend; p++) {
+ for (p = (const unsigned char *)str; p < pend; p++, length--) {
c = *p;
+ perr = p; /* Erroneous char is always the first of an invalid utf8 sequence... */
+ if (ELEM(c, 0xfe, 0xff, 0x00)) /* Those three values are not allowed in utf8 string. */
+ goto utf8_error;
if (c < 128)
continue;
if ((c & 0xc0) != 0xc0)
goto utf8_error;
- ab = trailingBytesForUTF8[c];
- if (length < ab)
+
+ /* Note that since we always increase p (and decrease length) by one byte in main loop, we only add/subtract
+ * extra utf8 bytes in code below
+ * (ab number, aka number of bytes remaining in the utf8 sequence after the initial one). */
+ ab = (int)utf8_skip_data[c] - 1;
+ if (length <= ab) {
goto utf8_error;
- length -= ab;
+ }
- p++;
/* Check top bits in the second byte */
+ p++;
+ length--;
if ((*p & 0xc0) != 0x80)
goto utf8_error;
/* Check for overlong sequences for each different length */
switch (ab) {
- /* Check for xx00 000x */
- case 1:
- if ((c & 0x3e) == 0) goto utf8_error;
- continue; /* We know there aren't any more bytes to check */
-
- /* Check for 1110 0000, xx0x xxxx */
- case 2:
- if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error;
- break;
-
- /* Check for 1111 0000, xx00 xxxx */
- case 3:
- if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error;
- break;
-
- /* Check for 1111 1000, xx00 0xxx */
- case 4:
- if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error;
- break;
-
- /* Check for leading 0xfe or 0xff,
- * and then for 1111 1100, xx00 00xx */
- case 5:
- if (c == 0xfe || c == 0xff ||
- (c == 0xfc && (*p & 0x3c) == 0)) goto utf8_error;
- break;
+ case 1:
+ /* Check for xx00 000x */
+ if ((c & 0x3e) == 0) goto utf8_error;
+ continue; /* We know there aren't any more bytes to check */
+
+ case 2:
+ /* Check for 1110 0000, xx0x xxxx */
+ if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error;
+ /* Some special cases, see section 5 of utf-8 decoder stress-test by Markus Kuhn
+ * (https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt). */
+ /* From section 5.1 (and 5.2) */
+ if (c == 0xed) {
+ if (*p == 0xa0 && *(p + 1) == 0x80) goto utf8_error;
+ if (*p == 0xad && *(p + 1) == 0xbf) goto utf8_error;
+ if (*p == 0xae && *(p + 1) == 0x80) goto utf8_error;
+ if (*p == 0xaf && *(p + 1) == 0xbf) goto utf8_error;
+ if (*p == 0xb0 && *(p + 1) == 0x80) goto utf8_error;
+ if (*p == 0xbe && *(p + 1) == 0x80) goto utf8_error;
+ if (*p == 0xbf && *(p + 1) == 0xbf) goto utf8_error;
+ }
+ /* From section 5.3 */
+ if (c == 0xef) {
+ if (*p == 0xbf && *(p + 1) == 0xbe) goto utf8_error;
+ if (*p == 0xbf && *(p + 1) == 0xbf) goto utf8_error;
+ }
+ break;
+
+ case 3:
+ /* Check for 1111 0000, xx00 xxxx */
+ if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error;
+ break;
+
+ case 4:
+ /* Check for 1111 1000, xx00 0xxx */
+ if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error;
+ break;
+
+ case 5:
+ /* Check for 1111 1100, xx00 00xx */
+ if (c == 0xfc && (*p & 0x3c) == 0) goto utf8_error;
+ break;
}
/* Check for valid bytes after the 2nd, if any; all must start 10 */
while (--ab > 0) {
- if ((*(p + 1) & 0xc0) != 0x80) goto utf8_error;
- p++; /* do this after so we get usable offset - campbell */
+ p++;
+ length--;
+ if ((*p & 0xc0) != 0x80) goto utf8_error;
}
}
@@ -130,18 +161,24 @@ int BLI_utf8_invalid_byte(const char *str, int length)
utf8_error:
- return (int)((const char *)p - (const char *)str) - 1;
+ return ((const char *)perr - (const char *)str);
}
-int BLI_utf8_invalid_strip(char *str, int length)
+/**
+ * Remove any invalid utf-8 byte (taking into account multi-bytes sequence of course).
+ *
+ * \return number of stripped bytes.
+ */
+int BLI_utf8_invalid_strip(char *str, size_t length)
{
- int bad_char, tot = 0;
+ ptrdiff_t bad_char;
+ int tot = 0;
BLI_assert(str[length] == '\0');
while ((bad_char = BLI_utf8_invalid_byte(str, length)) != -1) {
str += bad_char;
- length -= bad_char;
+ length -= (size_t)(bad_char + 1);
if (length == 0) {
/* last character bad, strip it */
@@ -151,7 +188,7 @@ int BLI_utf8_invalid_strip(char *str, int length)
}
else {
/* strip, keep looking */
- memmove(str, str + 1, (size_t)length);
+ memmove(str, str + 1, length + 1); /* +1 for NULL char! */
tot++;
}
}
@@ -162,31 +199,17 @@ int BLI_utf8_invalid_strip(char *str, int length)
/* compatible with BLI_strncpy, but esnure no partial utf8 chars */
-/* array copied from glib's gutf8.c,
- * note: this looks to be at odd's with 'trailingBytesForUTF8',
- * need to find out what gives here! - campbell */
-static const size_t utf8_skip_data[256] = {
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
-};
-
#define BLI_STR_UTF8_CPY(dst, src, maxncpy) \
{ \
size_t utf8_size; \
while (*src != '\0' && (utf8_size = utf8_skip_data[*src]) < maxncpy) {\
maxncpy -= utf8_size; \
switch (utf8_size) { \
- case 6: *dst ++ = *src ++; \
- case 5: *dst ++ = *src ++; \
- case 4: *dst ++ = *src ++; \
- case 3: *dst ++ = *src ++; \
- case 2: *dst ++ = *src ++; \
+ case 6: *dst ++ = *src ++; ATTR_FALLTHROUGH; \
+ case 5: *dst ++ = *src ++; ATTR_FALLTHROUGH; \
+ case 4: *dst ++ = *src ++; ATTR_FALLTHROUGH; \
+ case 3: *dst ++ = *src ++; ATTR_FALLTHROUGH; \
+ case 2: *dst ++ = *src ++; ATTR_FALLTHROUGH; \
case 1: *dst ++ = *src ++; \
} \
} \
diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c
new file mode 100644
index 00000000000..a693463a302
--- /dev/null
+++ b/source/blender/blenlib/intern/string_utils.c
@@ -0,0 +1,473 @@
+/*
+ * ***** 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) 2017 by the Blender FOundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenlib/intern/string_utils.c
+ * \ingroup bli
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_listBase.h"
+
+
+#ifdef __GNUC__
+# pragma GCC diagnostic error "-Wsign-conversion"
+#endif
+
+/**
+ * Looks for a numeric suffix preceded by delim character on the end of
+ * name, puts preceding part into *left and value of suffix into *nr.
+ * Returns the length of *left.
+ *
+ * Foo.001 -> "Foo", 1
+ * Returning the length of "Foo"
+ *
+ * \param left Where to return copy of part preceding delim
+ * \param nr Where to return value of numeric suffix
+ * \param name String to split
+ * \param delim Delimiter character
+ * \return Length of \a left
+ */
+size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
+{
+ const size_t name_len = strlen(name);
+
+ *nr = 0;
+ memcpy(left, name, (name_len + 1) * sizeof(char));
+
+ /* name doesn't end with a delimiter "foo." */
+ if ((name_len > 1 && name[name_len - 1] == delim) == 0) {
+ size_t a = name_len;
+ while (a--) {
+ if (name[a] == delim) {
+ left[a] = '\0'; /* truncate left part here */
+ *nr = atol(name + a + 1);
+ /* casting down to an int, can overflow for large numbers */
+ if (*nr < 0)
+ *nr = 0;
+ return a;
+ }
+ else if (isdigit(name[a]) == 0) {
+ /* non-numeric suffix - give up */
+ break;
+ }
+ }
+ }
+
+ return name_len;
+}
+
+static bool is_char_sep(const char c)
+{
+ return ELEM(c, '.', ' ', '-', '_');
+}
+
+/**
+ * based on `BLI_split_dirfile()` / `os.path.splitext()`,
+ * `"a.b.c"` -> (`"a.b"`, `".c"`).
+ */
+void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len)
+{
+ size_t len = BLI_strnlen(string, str_len);
+ size_t i;
+
+ r_body[0] = r_suf[0] = '\0';
+
+ for (i = len; i > 0; i--) {
+ if (is_char_sep(string[i])) {
+ BLI_strncpy(r_body, string, i + 1);
+ BLI_strncpy(r_suf, string + i, (len + 1) - i);
+ return;
+ }
+ }
+
+ memcpy(r_body, string, len + 1);
+}
+
+/**
+ * `"a.b.c"` -> (`"a."`, `"b.c"`)
+ */
+void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len)
+{
+ size_t len = BLI_strnlen(string, str_len);
+ size_t i;
+
+ r_body[0] = r_pre[0] = '\0';
+
+ for (i = 1; i < len; i++) {
+ if (is_char_sep(string[i])) {
+ i++;
+ BLI_strncpy(r_pre, string, i + 1);
+ BLI_strncpy(r_body, string + i, (len + 1) - i);
+ return;
+ }
+ }
+
+ BLI_strncpy(r_body, string, len);
+}
+
+/**
+ * Finds the best possible flipped (left/right) name. For renaming; check for unique names afterwards.
+ *
+ * \param r_name flipped name, assumed to be a pointer to a string of at least \a name_len size.
+ * \param from_name original name, assumed to be a pointer to a string of at least \a name_len size.
+ * \param strip_number If set, remove number extensions.
+ */
+void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len)
+{
+ size_t len;
+ char *prefix = alloca(name_len); /* The part before the facing */
+ char *suffix = alloca(name_len); /* The part after the facing */
+ char *replace = alloca(name_len); /* The replacement string */
+ char *number = alloca(name_len); /* The number extension string */
+ char *index = NULL;
+ bool is_set = false;
+
+ *prefix = *suffix = *replace = *number = '\0';
+
+ /* always copy the name, since this can be called with an uninitialized string */
+ BLI_strncpy(r_name, from_name, name_len);
+
+ len = BLI_strnlen(from_name, name_len);
+ if (len < 3) {
+ /* we don't do names like .R or .L */
+ return;
+ }
+
+ /* We first check the case with a .### extension, let's find the last period */
+ if (isdigit(r_name[len - 1])) {
+ index = strrchr(r_name, '.'); // last occurrence
+ if (index && isdigit(index[1])) { // doesnt handle case bone.1abc2 correct..., whatever!
+ if (strip_number == false) {
+ BLI_strncpy(number, index, name_len);
+ }
+ *index = 0;
+ len = BLI_strnlen(r_name, name_len);
+ }
+ }
+
+ BLI_strncpy(prefix, r_name, name_len);
+
+ /* first case; separator . - _ with extensions r R l L */
+ if ((len > 1) && is_char_sep(r_name[len - 2])) {
+ is_set = true;
+ switch (r_name[len - 1]) {
+ case 'l':
+ prefix[len - 1] = 0;
+ strcpy(replace, "r");
+ break;
+ case 'r':
+ prefix[len - 1] = 0;
+ strcpy(replace, "l");
+ break;
+ case 'L':
+ prefix[len - 1] = 0;
+ strcpy(replace, "R");
+ break;
+ case 'R':
+ prefix[len - 1] = 0;
+ strcpy(replace, "L");
+ break;
+ default:
+ is_set = false;
+ }
+ }
+
+ /* case; beginning with r R l L, with separator after it */
+ if (!is_set && is_char_sep(r_name[1])) {
+ is_set = true;
+ switch (r_name[0]) {
+ case 'l':
+ strcpy(replace, "r");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ case 'r':
+ strcpy(replace, "l");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ case 'L':
+ strcpy(replace, "R");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ case 'R':
+ strcpy(replace, "L");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ default:
+ is_set = false;
+ }
+ }
+
+ if (!is_set && len > 5) {
+ /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
+ if (((index = BLI_strcasestr(prefix, "right")) == prefix) ||
+ (index == prefix + len - 5))
+ {
+ is_set = true;
+ if (index[0] == 'r') {
+ strcpy(replace, "left");
+ }
+ else {
+ strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left");
+ }
+ *index = 0;
+ BLI_strncpy(suffix, index + 5, name_len);
+ }
+ else if (((index = BLI_strcasestr(prefix, "left")) == prefix) ||
+ (index == prefix + len - 4))
+ {
+ is_set = true;
+ if (index[0] == 'l') {
+ strcpy(replace, "right");
+ }
+ else {
+ strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right");
+ }
+ *index = 0;
+ BLI_strncpy(suffix, index + 4, name_len);
+ }
+ }
+
+ BLI_snprintf(r_name, name_len, "%s%s%s%s", prefix, replace, suffix, number);
+}
+
+
+/* Unique name utils. */
+
+/**
+ * Ensures name is unique (according to criteria specified by caller in unique_check callback),
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param unique_check Return true if name is not unique
+ * \param arg Additional arg to unique_check--meaning is up to caller
+ * \param defname To initialize name if latter is empty
+ * \param delim Delimits numeric suffix in name
+ * \param name Name to be ensured unique
+ * \param name_len Maximum length of name area
+ * \return true if there if the name was changed
+ */
+bool BLI_uniquename_cb(
+ UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len)
+{
+ if (name[0] == '\0') {
+ BLI_strncpy(name, defname, name_len);
+ }
+
+ if (unique_check(arg, name)) {
+ char numstr[16];
+ char *tempname = alloca(name_len);
+ char *left = alloca(name_len);
+ int number;
+ size_t len = BLI_split_name_num(left, &number, name, delim);
+ do {
+ /* add 1 to account for \0 */
+ const size_t numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1;
+
+ /* highly unlikely the string only has enough room for the number
+ * but support anyway */
+ if ((len == 0) || (numlen >= name_len)) {
+ /* number is know not to be utf-8 */
+ BLI_strncpy(tempname, numstr, name_len);
+ }
+ else {
+ char *tempname_buf;
+ tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen);
+ memcpy(tempname_buf, numstr, numlen);
+ }
+ } while (unique_check(arg, tempname));
+
+ BLI_strncpy(name, tempname, name_len);
+
+ return true;
+ }
+
+ return false;
+}
+
+/* little helper macro for BLI_uniquename */
+#ifndef GIVE_STRADDR
+# define GIVE_STRADDR(data, offset) ( ((char *)data) + offset)
+#endif
+
+/* Generic function to set a unique name. It is only designed to be used in situations
+ * where the name is part of the struct.
+ *
+ * For places where this is used, see constraint.c for example...
+ *
+ * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
+ * len: maximum length of string (to prevent overflows, etc.)
+ * defname: the name that should be used by default if none is specified already
+ * delim: the character which acts as a delimiter between parts of the name
+ */
+static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
+{
+ Link *link;
+
+ for (link = list->first; link; link = link->next) {
+ if (link != vlink) {
+ if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool uniquename_unique_check(void *arg, const char *name)
+{
+ struct {ListBase *lb; void *vlink; int name_offs; } *data = arg;
+ return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
+}
+
+/**
+ * Ensures that the specified block has a unique name within the containing list,
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param list List containing the block
+ * \param vlink The block to check the name for
+ * \param defname To initialize block name if latter is empty
+ * \param delim Delimits numeric suffix in name
+ * \param name_offs Offset of name within block structure
+ * \param name_len Maximum length of name area
+ */
+bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t name_len)
+{
+ struct {ListBase *lb; void *vlink; int name_offs; } data;
+ data.lb = list;
+ data.vlink = vlink;
+ data.name_offs = name_offs;
+
+ BLI_assert(name_len > 1);
+
+ /* See if we are given an empty string */
+ if (ELEM(NULL, vlink, defname))
+ return false;
+
+ return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
+}
+
+/* ------------------------------------------------------------------------- */
+/** \name Join Strings
+ *
+ * For non array versions of these functions, use the macros:
+ * - #BLI_string_joinN
+ * - #BLI_string_join_by_sep_charN
+ * - #BLI_string_join_by_sep_char_with_tableN
+ *
+ * \{ */
+
+/**
+ * Join an array of strings into a newly allocated, null terminated string.
+ */
+char *BLI_string_join_arrayN(
+ const char *strings[], uint strings_len)
+{
+ uint total_len = 1;
+ for (uint i = 0; i < strings_len; i++) {
+ total_len += strlen(strings[i]);
+ }
+ char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
+ char *c = result;
+ for (uint i = 0; i < strings_len; i++) {
+ c += BLI_strcpy_rlen(c, strings[i]);
+ }
+ return result;
+}
+
+/**
+ * A version of #BLI_string_joinN that takes a separator which can be any character including '\0'.
+ */
+char *BLI_string_join_array_by_sep_charN(
+ char sep, const char *strings[], uint strings_len)
+{
+ uint total_len = 0;
+ for (uint i = 0; i < strings_len; i++) {
+ total_len += strlen(strings[i]) + 1;
+ }
+ if (total_len == 0) {
+ total_len = 1;
+ }
+
+ char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
+ char *c = result;
+ if (strings_len != 0) {
+ for (uint i = 0; i < strings_len; i++) {
+ c += BLI_strcpy_rlen(c, strings[i]);
+ *c = sep;
+ c++;
+ }
+ c--;
+ }
+ *c = '\0';
+ return result;
+}
+
+/**
+ * A version of #BLI_string_join_array_by_sep_charN that takes a table array.
+ * The new location of each string is written into this array.
+ */
+char *BLI_string_join_array_by_sep_char_with_tableN(
+ char sep, char *table[], const char *strings[], uint strings_len)
+{
+ uint total_len = 0;
+ for (uint i = 0; i < strings_len; i++) {
+ total_len += strlen(strings[i]) + 1;
+ }
+ if (total_len == 0) {
+ total_len = 1;
+ }
+
+ char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
+ char *c = result;
+ if (strings_len != 0) {
+ for (uint i = 0; i < strings_len; i++) {
+ table[i] = c; /* <-- only difference to BLI_string_join_array_by_sep_charN. */
+ c += BLI_strcpy_rlen(c, strings[i]);
+ *c = sep;
+ c++;
+ }
+ c--;
+ }
+ *c = '\0';
+ return result;
+}
+
+/** \} */
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index fc2d9674c2f..e050f3148b8 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -48,6 +48,39 @@
*/
#define MEMPOOL_SIZE 256
+/* Number of tasks which are pushed directly to local thread queue.
+ *
+ * This allows thread to fetch next task without locking the whole queue.
+ */
+#define LOCAL_QUEUE_SIZE 1
+
+/* Number of tasks which are allowed to be scheduled in a delayed manner.
+ *
+ * This allows to use less locks per graph node children schedule. More details
+ * could be found at TaskThreadLocalStorage::do_delayed_push.
+ */
+#define DELAYED_QUEUE_SIZE 4096
+
+#ifndef NDEBUG
+# define ASSERT_THREAD_ID(scheduler, thread_id) \
+ do { \
+ if (!BLI_thread_is_main()) { \
+ TaskThread *thread = pthread_getspecific(scheduler->tls_id_key); \
+ if (thread == NULL) { \
+ BLI_assert(thread_id == 0); \
+ } \
+ else { \
+ BLI_assert(thread_id == thread->id); \
+ } \
+ } \
+ else { \
+ BLI_assert(thread_id == 0); \
+ } \
+ } while (false)
+#else
+# define ASSERT_THREAD_ID(scheduler, thread_id)
+#endif
+
typedef struct Task {
struct Task *next, *prev;
@@ -102,13 +135,35 @@ typedef struct TaskMemPoolStats {
} TaskMemPoolStats;
#endif
+typedef struct TaskThreadLocalStorage {
+ /* Memory pool for faster task allocation.
+ * The idea is to re-use memory of finished/discarded tasks by this thread.
+ */
+ TaskMemPool task_mempool;
+
+ /* Local queue keeps thread alive by keeping small amount of tasks ready
+ * to be picked up without causing global thread locks for synchronization.
+ */
+ int num_local_queue;
+ Task *local_queue[LOCAL_QUEUE_SIZE];
+
+ /* Thread can be marked for delayed tasks push. This is helpful when it's
+ * know that lots of subsequent task pushed will happen from the same thread
+ * without "interrupting" for task execution.
+ *
+ * We try to accumulate as much tasks as possible in a local queue without
+ * any locks first, and then we push all of them into a scheduler's queue
+ * from within a single mutex lock.
+ */
+ bool do_delayed_push;
+ int num_delayed_queue;
+ Task *delayed_queue[DELAYED_QUEUE_SIZE];
+} TaskThreadLocalStorage;
+
struct TaskPool {
TaskScheduler *scheduler;
volatile size_t num;
- volatile size_t done;
- size_t num_threads;
- size_t currently_running_tasks;
ThreadMutex num_mutex;
ThreadCondition num_cond;
@@ -116,6 +171,11 @@ struct TaskPool {
ThreadMutex user_mutex;
volatile bool do_cancel;
+ volatile bool do_work;
+
+ volatile bool is_suspended;
+ ListBase suspended_queue;
+ size_t num_suspended;
/* If set, this pool may never be work_and_wait'ed, which means TaskScheduler
* has to use its special background fallback thread in case we are in
@@ -123,16 +183,20 @@ struct TaskPool {
*/
bool run_in_background;
- /* This pool is used for caching task pointers for thread id 0.
- * This could either point to a global scheduler's task_mempool[0] if the
- * pool is handled form the main thread or point to task_mempool_local
- * otherwise.
- *
- * This way we solve possible threading conflicts accessing same global
- * memory pool from multiple threads from which wait_work() is called.
+ /* This is a task scheduler's ID of a thread at which pool was constructed.
+ * It will be used to access task TLS.
+ */
+ int thread_id;
+
+ /* For the pools which are created from non-main thread which is not a
+ * scheduler worker thread we can't re-use any of scheduler's threads TLS
+ * and have to use our own one.
*/
- TaskMemPool *task_mempool;
- TaskMemPool task_mempool_local;
+ bool use_local_tls;
+ TaskThreadLocalStorage local_tls;
+#ifndef NDEBUG
+ pthread_t creator_thread_id;
+#endif
#ifdef DEBUG_STATS
TaskMemPoolStats *mempool_stats;
@@ -142,7 +206,6 @@ struct TaskPool {
struct TaskScheduler {
pthread_t *threads;
struct TaskThread *task_threads;
- TaskMemPool *task_mempool;
int num_threads;
bool background_thread_only;
@@ -151,15 +214,19 @@ struct TaskScheduler {
ThreadCondition queue_cond;
volatile bool do_exit;
+
+ /* NOTE: In pthread's TLS we store the whole TaskThread structure. */
+ pthread_key_t tls_id_key;
};
typedef struct TaskThread {
TaskScheduler *scheduler;
int id;
+ TaskThreadLocalStorage tls;
} TaskThread;
/* Helper */
-static void task_data_free(Task *task, const int thread_id)
+BLI_INLINE void task_data_free(Task *task, const int thread_id)
{
if (task->free_taskdata) {
if (task->freedata) {
@@ -171,28 +238,54 @@ static void task_data_free(Task *task, const int thread_id)
}
}
-BLI_INLINE TaskMemPool *get_task_mempool(TaskPool *pool, const int thread_id)
+BLI_INLINE void initialize_task_tls(TaskThreadLocalStorage *tls)
+{
+ memset(tls, 0, sizeof(TaskThreadLocalStorage));
+}
+
+BLI_INLINE TaskThreadLocalStorage *get_task_tls(TaskPool *pool,
+ const int thread_id)
{
+ TaskScheduler *scheduler = pool->scheduler;
+ BLI_assert(thread_id >= 0);
+ BLI_assert(thread_id <= scheduler->num_threads);
+ if (pool->use_local_tls && thread_id == 0) {
+ BLI_assert(pool->thread_id == 0);
+ BLI_assert(!BLI_thread_is_main());
+ BLI_assert(pthread_equal(pthread_self(), pool->creator_thread_id));
+ return &pool->local_tls;
+ }
if (thread_id == 0) {
- return pool->task_mempool;
+ BLI_assert(BLI_thread_is_main());
+ return &scheduler->task_threads[pool->thread_id].tls;
+ }
+ return &scheduler->task_threads[thread_id].tls;
+}
+
+BLI_INLINE void free_task_tls(TaskThreadLocalStorage *tls)
+{
+ TaskMemPool *task_mempool = &tls->task_mempool;
+ for (int i = 0; i < task_mempool->num_tasks; ++i) {
+ MEM_freeN(task_mempool->tasks[i]);
}
- return &pool->scheduler->task_mempool[thread_id];
}
static Task *task_alloc(TaskPool *pool, const int thread_id)
{
- assert(thread_id <= pool->scheduler->num_threads);
+ BLI_assert(thread_id <= pool->scheduler->num_threads);
if (thread_id != -1) {
- assert(thread_id >= 0);
- TaskMemPool *mem_pool = get_task_mempool(pool, thread_id);
+ BLI_assert(thread_id >= 0);
+ BLI_assert(thread_id <= pool->scheduler->num_threads);
+ TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
+ TaskMemPool *task_mempool = &tls->task_mempool;
/* Try to re-use task memory from a thread local storage. */
- if (mem_pool->num_tasks > 0) {
- --mem_pool->num_tasks;
+ if (task_mempool->num_tasks > 0) {
+ --task_mempool->num_tasks;
/* Success! We've just avoided task allocation. */
#ifdef DEBUG_STATS
pool->mempool_stats[thread_id].num_reuse++;
#endif
- return mem_pool->tasks[mem_pool->num_tasks];
+ return task_mempool->tasks[task_mempool->num_tasks];
}
/* We are doomed to allocate new task data. */
#ifdef DEBUG_STATS
@@ -205,13 +298,17 @@ static Task *task_alloc(TaskPool *pool, const int thread_id)
static void task_free(TaskPool *pool, Task *task, const int thread_id)
{
task_data_free(task, thread_id);
- assert(thread_id >= 0);
- assert(thread_id <= pool->scheduler->num_threads);
- TaskMemPool *mem_pool = get_task_mempool(pool, thread_id);
- if (mem_pool->num_tasks < MEMPOOL_SIZE - 1) {
+ BLI_assert(thread_id >= 0);
+ BLI_assert(thread_id <= pool->scheduler->num_threads);
+ if (thread_id == 0) {
+ BLI_assert(pool->use_local_tls || BLI_thread_is_main());
+ }
+ TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
+ TaskMemPool *task_mempool = &tls->task_mempool;
+ if (task_mempool->num_tasks < MEMPOOL_SIZE - 1) {
/* Successfully allowed the task to be re-used later. */
- mem_pool->tasks[mem_pool->num_tasks] = task;
- ++mem_pool->num_tasks;
+ task_mempool->tasks[task_mempool->num_tasks] = task;
+ ++task_mempool->num_tasks;
}
else {
/* Local storage saturated, no other way than just discard
@@ -237,8 +334,6 @@ static void task_pool_num_decrease(TaskPool *pool, size_t done)
BLI_assert(pool->num >= done);
pool->num -= done;
- atomic_sub_and_fetch_z(&pool->currently_running_tasks, done);
- pool->done += done;
if (pool->num == 0)
BLI_condition_notify_all(&pool->num_cond);
@@ -246,11 +341,11 @@ static void task_pool_num_decrease(TaskPool *pool, size_t done)
BLI_mutex_unlock(&pool->num_mutex);
}
-static void task_pool_num_increase(TaskPool *pool)
+static void task_pool_num_increase(TaskPool *pool, size_t new)
{
BLI_mutex_lock(&pool->num_mutex);
- pool->num++;
+ pool->num += new;
BLI_condition_notify_all(&pool->num_cond);
BLI_mutex_unlock(&pool->num_mutex);
@@ -292,17 +387,10 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task
continue;
}
- if (atomic_add_and_fetch_z(&pool->currently_running_tasks, 1) <= pool->num_threads ||
- pool->num_threads == 0)
- {
- *task = current_task;
- found_task = true;
- BLI_remlink(&scheduler->queue, *task);
- break;
- }
- else {
- atomic_sub_and_fetch_z(&pool->currently_running_tasks, 1);
- }
+ *task = current_task;
+ found_task = true;
+ BLI_remlink(&scheduler->queue, *task);
+ break;
}
if (!found_task)
BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex);
@@ -313,23 +401,51 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task
return true;
}
+BLI_INLINE void handle_local_queue(TaskThreadLocalStorage *tls,
+ const int thread_id)
+{
+ BLI_assert(!tls->do_delayed_push);
+ while (tls->num_local_queue > 0) {
+ /* We pop task from queue before handling it so handler of the task can
+ * push next job to the local queue.
+ */
+ tls->num_local_queue--;
+ Task *local_task = tls->local_queue[tls->num_local_queue];
+ /* TODO(sergey): Double-check work_and_wait() doesn't handle other's
+ * pool tasks.
+ */
+ TaskPool *local_pool = local_task->pool;
+ local_task->run(local_pool, local_task->taskdata, thread_id);
+ task_free(local_pool, local_task, thread_id);
+ }
+ BLI_assert(!tls->do_delayed_push);
+}
+
static void *task_scheduler_thread_run(void *thread_p)
{
TaskThread *thread = (TaskThread *) thread_p;
+ TaskThreadLocalStorage *tls = &thread->tls;
TaskScheduler *scheduler = thread->scheduler;
int thread_id = thread->id;
Task *task;
+ pthread_setspecific(scheduler->tls_id_key, thread);
+
/* keep popping off tasks */
while (task_scheduler_thread_wait_pop(scheduler, &task)) {
TaskPool *pool = task->pool;
/* run task */
+ BLI_assert(!tls->do_delayed_push);
task->run(pool, task->taskdata, thread_id);
+ BLI_assert(!tls->do_delayed_push);
/* delete task */
task_free(pool, task, thread_id);
+ /* Handle all tasks from local queue. */
+ handle_local_queue(tls, thread_id);
+
/* notify pool task was done */
task_pool_num_decrease(pool, 1);
}
@@ -359,30 +475,35 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads)
/* Add background-only thread if needed. */
if (num_threads == 0) {
- scheduler->background_thread_only = true;
- num_threads = 1;
+ scheduler->background_thread_only = true;
+ num_threads = 1;
}
+ scheduler->task_threads = MEM_mallocN(sizeof(TaskThread) * (num_threads + 1),
+ "TaskScheduler task threads");
+
+ /* Initialize TLS for main thread. */
+ initialize_task_tls(&scheduler->task_threads[0].tls);
+
+ pthread_key_create(&scheduler->tls_id_key, NULL);
+
/* launch threads that will be waiting for work */
if (num_threads > 0) {
int i;
scheduler->num_threads = num_threads;
scheduler->threads = MEM_callocN(sizeof(pthread_t) * num_threads, "TaskScheduler threads");
- scheduler->task_threads = MEM_callocN(sizeof(TaskThread) * num_threads, "TaskScheduler task threads");
for (i = 0; i < num_threads; i++) {
- TaskThread *thread = &scheduler->task_threads[i];
+ TaskThread *thread = &scheduler->task_threads[i + 1];
thread->scheduler = scheduler;
thread->id = i + 1;
+ initialize_task_tls(&thread->tls);
if (pthread_create(&scheduler->threads[i], NULL, task_scheduler_thread_run, thread) != 0) {
fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads);
}
}
-
- scheduler->task_mempool = MEM_callocN(sizeof(*scheduler->task_mempool) * (num_threads + 1),
- "TaskScheduler task_mempool");
}
return scheduler;
@@ -398,6 +519,8 @@ void BLI_task_scheduler_free(TaskScheduler *scheduler)
BLI_condition_notify_all(&scheduler->queue_cond);
BLI_mutex_unlock(&scheduler->queue_mutex);
+ pthread_key_delete(scheduler->tls_id_key);
+
/* delete threads */
if (scheduler->threads) {
int i;
@@ -412,17 +535,12 @@ void BLI_task_scheduler_free(TaskScheduler *scheduler)
/* Delete task thread data */
if (scheduler->task_threads) {
- MEM_freeN(scheduler->task_threads);
- }
-
- /* Delete task memory pool */
- if (scheduler->task_mempool) {
- for (int i = 0; i <= scheduler->num_threads; ++i) {
- for (int j = 0; j < scheduler->task_mempool[i].num_tasks; ++j) {
- MEM_freeN(scheduler->task_mempool[i].tasks[j]);
- }
+ for (int i = 0; i < scheduler->num_threads + 1; ++i) {
+ TaskThreadLocalStorage *tls = &scheduler->task_threads[i].tls;
+ free_task_tls(tls);
}
- MEM_freeN(scheduler->task_mempool);
+
+ MEM_freeN(scheduler->task_threads);
}
/* delete leftover tasks */
@@ -445,7 +563,7 @@ int BLI_task_scheduler_num_threads(TaskScheduler *scheduler)
static void task_scheduler_push(TaskScheduler *scheduler, Task *task, TaskPriority priority)
{
- task_pool_num_increase(task->pool);
+ task_pool_num_increase(task->pool, 1);
/* add task to queue */
BLI_mutex_lock(&scheduler->queue_mutex);
@@ -459,6 +577,27 @@ static void task_scheduler_push(TaskScheduler *scheduler, Task *task, TaskPriori
BLI_mutex_unlock(&scheduler->queue_mutex);
}
+static void task_scheduler_push_all(TaskScheduler *scheduler,
+ TaskPool *pool,
+ Task **tasks,
+ int num_tasks)
+{
+ if (num_tasks == 0) {
+ return;
+ }
+
+ task_pool_num_increase(pool, num_tasks);
+
+ BLI_mutex_lock(&scheduler->queue_mutex);
+
+ for (int i = 0; i < num_tasks; i++) {
+ BLI_addhead(&scheduler->queue, tasks[i]);
+ }
+
+ BLI_condition_notify_all(&scheduler->queue_cond);
+ BLI_mutex_unlock(&scheduler->queue_mutex);
+}
+
static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
{
Task *task, *nexttask;
@@ -471,7 +610,7 @@ static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
nexttask = task->next;
if (task->pool == pool) {
- task_data_free(task, 0);
+ task_data_free(task, pool->thread_id);
BLI_freelinkN(&scheduler->queue, task);
done++;
@@ -486,7 +625,10 @@ static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
/* Task Pool */
-static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, const bool is_background)
+static TaskPool *task_pool_create_ex(TaskScheduler *scheduler,
+ void *userdata,
+ const bool is_background,
+ const bool is_suspended)
{
TaskPool *pool = MEM_mallocN(sizeof(TaskPool), "TaskPool");
@@ -504,11 +646,13 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, c
pool->scheduler = scheduler;
pool->num = 0;
- pool->done = 0;
- pool->num_threads = 0;
- pool->currently_running_tasks = 0;
pool->do_cancel = false;
+ pool->do_work = false;
+ pool->is_suspended = is_suspended;
+ pool->num_suspended = 0;
+ pool->suspended_queue.first = pool->suspended_queue.last = NULL;
pool->run_in_background = is_background;
+ pool->use_local_tls = false;
BLI_mutex_init(&pool->num_mutex);
BLI_condition_init(&pool->num_cond);
@@ -517,11 +661,26 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, c
BLI_mutex_init(&pool->user_mutex);
if (BLI_thread_is_main()) {
- pool->task_mempool = scheduler->task_mempool;
+ pool->thread_id = 0;
}
else {
- pool->task_mempool = &pool->task_mempool_local;
- pool->task_mempool_local.num_tasks = 0;
+ TaskThread *thread = pthread_getspecific(scheduler->tls_id_key);
+ if (thread == NULL) {
+ /* NOTE: Task pool is created from non-main thread which is not
+ * managed by the task scheduler. We identify ourselves as thread ID
+ * 0 but we do not use scheduler's TLS storage and use our own
+ * instead to avoid any possible threading conflicts.
+ */
+ pool->thread_id = 0;
+ pool->use_local_tls = true;
+#ifndef NDEBUG
+ pool->creator_thread_id = pthread_self();
+#endif
+ initialize_task_tls(&pool->local_tls);
+ }
+ else {
+ pool->thread_id = thread->id;
+ }
}
#ifdef DEBUG_STATS
@@ -548,7 +707,7 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, c
*/
TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
{
- return task_pool_create_ex(scheduler, userdata, false);
+ return task_pool_create_ex(scheduler, userdata, false, false);
}
/**
@@ -563,25 +722,28 @@ TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
*/
TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void *userdata)
{
- return task_pool_create_ex(scheduler, userdata, true);
+ return task_pool_create_ex(scheduler, userdata, true, false);
+}
+
+/**
+ * Similar to BLI_task_pool_create() but does not schedule any tasks for execution
+ * for until BLI_task_pool_work_and_wait() is called. This helps reducing therading
+ * overhead when pushing huge amount of small initial tasks from the main thread.
+ */
+TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler, void *userdata)
+{
+ return task_pool_create_ex(scheduler, userdata, false, true);
}
void BLI_task_pool_free(TaskPool *pool)
{
- BLI_task_pool_stop(pool);
+ BLI_task_pool_cancel(pool);
BLI_mutex_end(&pool->num_mutex);
BLI_condition_end(&pool->num_cond);
BLI_mutex_end(&pool->user_mutex);
- /* Free local memory pool, those pointers are lost forever. */
- if (pool->task_mempool == &pool->task_mempool_local) {
- for (int i = 0; i < pool->task_mempool_local.num_tasks; i++) {
- MEM_freeN(pool->task_mempool_local.tasks[i]);
- }
- }
-
#ifdef DEBUG_STATS
printf("Thread ID Allocated Reused Discarded\n");
for (int i = 0; i < pool->scheduler->num_threads + 1; ++i) {
@@ -594,24 +756,68 @@ void BLI_task_pool_free(TaskPool *pool)
MEM_freeN(pool->mempool_stats);
#endif
+ if (pool->use_local_tls) {
+ free_task_tls(&pool->local_tls);
+ }
+
MEM_freeN(pool);
BLI_end_threaded_malloc();
}
+BLI_INLINE bool task_can_use_local_queues(TaskPool *pool, int thread_id)
+{
+ return (thread_id != -1 && (thread_id != pool->thread_id || pool->do_work));
+}
+
static void task_pool_push(
TaskPool *pool, TaskRunFunction run, void *taskdata,
bool free_taskdata, TaskFreeFunction freedata, TaskPriority priority,
int thread_id)
{
+ /* Allocate task and fill it's properties. */
Task *task = task_alloc(pool, thread_id);
-
task->run = run;
task->taskdata = taskdata;
task->free_taskdata = free_taskdata;
task->freedata = freedata;
task->pool = pool;
-
+ /* For suspended pools we put everything yo a global queue first
+ * and exit as soon as possible.
+ *
+ * This tasks will be moved to actual execution when pool is
+ * activated by work_and_wait().
+ */
+ if (pool->is_suspended) {
+ BLI_addhead(&pool->suspended_queue, task);
+ atomic_fetch_and_add_z(&pool->num_suspended, 1);
+ return;
+ }
+ /* Populate to any local queue first, this is cheapest push ever. */
+ if (task_can_use_local_queues(pool, thread_id)) {
+ ASSERT_THREAD_ID(pool->scheduler, thread_id);
+ TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
+ /* Try to push to a local execution queue.
+ * These tasks will be picked up next.
+ */
+ if (tls->num_local_queue < LOCAL_QUEUE_SIZE) {
+ tls->local_queue[tls->num_local_queue] = task;
+ tls->num_local_queue++;
+ return;
+ }
+ /* If we are in the delayed tasks push mode, we push tasks to a
+ * temporary local queue first without any locks, and then move them
+ * to global execution queue with a single lock.
+ */
+ if (tls->do_delayed_push && tls->num_delayed_queue < DELAYED_QUEUE_SIZE) {
+ tls->delayed_queue[tls->num_delayed_queue] = task;
+ tls->num_delayed_queue++;
+ return;
+ }
+ }
+ /* Do push to a global execution ppol, slowest possible method,
+ * causes quite reasonable amount of threading overhead.
+ */
task_scheduler_push(pool->scheduler, task, priority);
}
@@ -636,8 +842,25 @@ void BLI_task_pool_push_from_thread(TaskPool *pool, TaskRunFunction run,
void BLI_task_pool_work_and_wait(TaskPool *pool)
{
+ TaskThreadLocalStorage *tls = get_task_tls(pool, pool->thread_id);
TaskScheduler *scheduler = pool->scheduler;
+ if (atomic_fetch_and_and_uint8((uint8_t *)&pool->is_suspended, 0)) {
+ if (pool->num_suspended) {
+ task_pool_num_increase(pool, pool->num_suspended);
+ BLI_mutex_lock(&scheduler->queue_mutex);
+
+ BLI_movelisttolist(&scheduler->queue, &pool->suspended_queue);
+
+ BLI_condition_notify_all(&scheduler->queue_cond);
+ BLI_mutex_unlock(&scheduler->queue_mutex);
+ }
+ }
+
+ pool->do_work = true;
+
+ ASSERT_THREAD_ID(pool->scheduler, pool->thread_id);
+
BLI_mutex_lock(&pool->num_mutex);
while (pool->num != 0) {
@@ -651,16 +874,12 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
/* find task from this pool. if we get a task from another pool,
* we can get into deadlock */
- if (pool->num_threads == 0 ||
- pool->currently_running_tasks < pool->num_threads)
- {
- for (task = scheduler->queue.first; task; task = task->next) {
- if (task->pool == pool) {
- work_task = task;
- found_task = true;
- BLI_remlink(&scheduler->queue, task);
- break;
- }
+ for (task = scheduler->queue.first; task; task = task->next) {
+ if (task->pool == pool) {
+ work_task = task;
+ found_task = true;
+ BLI_remlink(&scheduler->queue, task);
+ break;
}
}
@@ -669,11 +888,15 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
/* if found task, do it, otherwise wait until other tasks are done */
if (found_task) {
/* run task */
- atomic_add_and_fetch_z(&pool->currently_running_tasks, 1);
- work_task->run(pool, work_task->taskdata, 0);
+ BLI_assert(!tls->do_delayed_push);
+ work_task->run(pool, work_task->taskdata, pool->thread_id);
+ BLI_assert(!tls->do_delayed_push);
/* delete task */
- task_free(pool, task, 0);
+ task_free(pool, task, pool->thread_id);
+
+ /* Handle all tasks from local queue. */
+ handle_local_queue(tls, pool->thread_id);
/* notify pool task was done */
task_pool_num_decrease(pool, 1);
@@ -688,22 +911,8 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
}
BLI_mutex_unlock(&pool->num_mutex);
-}
-
-int BLI_pool_get_num_threads(TaskPool *pool)
-{
- if (pool->num_threads != 0) {
- return pool->num_threads;
- }
- else {
- return BLI_task_scheduler_num_threads(pool->scheduler);
- }
-}
-void BLI_pool_set_num_threads(TaskPool *pool, int num_threads)
-{
- /* NOTE: Don't try to modify threads while tasks are running! */
- pool->num_threads = num_threads;
+ handle_local_queue(tls, pool->thread_id);
}
void BLI_task_pool_cancel(TaskPool *pool)
@@ -721,13 +930,6 @@ void BLI_task_pool_cancel(TaskPool *pool)
pool->do_cancel = false;
}
-void BLI_task_pool_stop(TaskPool *pool)
-{
- task_scheduler_clear(pool->scheduler, pool);
-
- BLI_assert(pool->num == 0);
-}
-
bool BLI_task_pool_canceled(TaskPool *pool)
{
return pool->do_cancel;
@@ -743,9 +945,28 @@ ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool)
return &pool->user_mutex;
}
-size_t BLI_task_pool_tasks_done(TaskPool *pool)
+void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id)
+{
+ if (task_can_use_local_queues(pool, thread_id)) {
+ ASSERT_THREAD_ID(pool->scheduler, thread_id);
+ TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
+ tls->do_delayed_push = true;
+ }
+}
+
+void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id)
{
- return pool->done;
+ if (task_can_use_local_queues(pool, thread_id)) {
+ ASSERT_THREAD_ID(pool->scheduler, thread_id);
+ TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
+ BLI_assert(tls->do_delayed_push);
+ task_scheduler_push_all(pool->scheduler,
+ pool,
+ tls->delayed_queue,
+ tls->num_delayed_queue);
+ tls->do_delayed_push = false;
+ tls->num_delayed_queue = 0;
+ }
}
/* Parallel range routines */
@@ -783,7 +1004,7 @@ BLI_INLINE bool parallel_range_next_iter_get(
int * __restrict iter, int * __restrict count)
{
uint32_t uval = atomic_fetch_and_add_uint32((uint32_t *)(&state->iter), state->chunk_size);
- int previter = *(int32_t*)&uval;
+ int previter = *(int32_t *)&uval;
*iter = previter;
*count = max_ii(0, min_ii(state->chunk_size, state->stop - previter));
@@ -906,7 +1127,7 @@ static void task_parallel_range_ex(
atomic_fetch_and_add_uint32((uint32_t *)(&state.iter), 0);
if (use_userdata_chunk) {
- userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
+ userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
}
for (i = 0; i < num_tasks; i++) {
@@ -918,7 +1139,8 @@ static void task_parallel_range_ex(
BLI_task_pool_push_from_thread(task_pool,
parallel_range_func,
userdata_chunk_local, false,
- TASK_PRIORITY_HIGH, 0);
+ TASK_PRIORITY_HIGH,
+ task_pool->thread_id);
}
BLI_task_pool_work_and_wait(task_pool);
@@ -1124,7 +1346,8 @@ void BLI_task_parallel_listbase(
BLI_task_pool_push_from_thread(task_pool,
parallel_listbase_func,
NULL, false,
- TASK_PRIORITY_HIGH, 0);
+ TASK_PRIORITY_HIGH,
+ task_pool->thread_id);
}
BLI_task_pool_work_and_wait(task_pool);
diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c
index b60981802aa..abf611d1245 100644
--- a/source/blender/blenlib/intern/threads.c
+++ b/source/blender/blenlib/intern/threads.c
@@ -54,6 +54,8 @@
# include <sys/time.h>
#endif
+#include "atomic_ops.h"
+
#if defined(__APPLE__) && defined(_OPENMP) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2) && !defined(__clang__)
# define USE_APPLE_OMP_FIX
#endif
@@ -124,7 +126,7 @@ static pthread_mutex_t _colormanage_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _fftw_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _view3d_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t mainid;
-static int thread_levels = 0; /* threads can be invoked inside threads */
+static unsigned int thread_levels = 0; /* threads can be invoked inside threads */
static int num_threads_override = 0;
/* just a max for security reasons */
@@ -198,9 +200,9 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
tslot->avail = 1;
}
}
-
- BLI_spin_lock(&_malloc_lock);
- if (thread_levels == 0) {
+
+ unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1);
+ if (level == 0) {
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
#ifdef USE_APPLE_OMP_FIX
@@ -210,9 +212,6 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
thread_tls_data = pthread_getspecific(gomp_tls_key);
#endif
}
-
- thread_levels++;
- BLI_spin_unlock(&_malloc_lock);
}
/* amount of available threads */
@@ -331,11 +330,10 @@ void BLI_end_threads(ListBase *threadbase)
BLI_freelistN(threadbase);
}
- BLI_spin_lock(&_malloc_lock);
- thread_levels--;
- if (thread_levels == 0)
+ unsigned int level = atomic_sub_and_fetch_u(&thread_levels, 1);
+ if (level == 0) {
MEM_set_lock_callback(NULL, NULL);
- BLI_spin_unlock(&_malloc_lock);
+ }
}
/* System Information */
@@ -812,26 +810,22 @@ void BLI_thread_queue_wait_finish(ThreadQueue *queue)
void BLI_begin_threaded_malloc(void)
{
- /* Used for debug only */
- /* BLI_assert(thread_levels >= 0); */
-
- BLI_spin_lock(&_malloc_lock);
- if (thread_levels == 0) {
+ unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1);
+ if (level == 0) {
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
+ /* There is a little chance that two threads will meed to acces to a
+ * scheduler which was not yet created from main thread. which could
+ * cause scheduler created multiple times.
+ */
+ BLI_task_scheduler_get();
}
- thread_levels++;
- BLI_spin_unlock(&_malloc_lock);
}
void BLI_end_threaded_malloc(void)
{
- /* Used for debug only */
- /* BLI_assert(thread_levels >= 0); */
-
- BLI_spin_lock(&_malloc_lock);
- thread_levels--;
- if (thread_levels == 0)
+ unsigned int level = atomic_sub_and_fetch_u(&thread_levels, 1);
+ if (level == 0) {
MEM_set_lock_callback(NULL, NULL);
- BLI_spin_unlock(&_malloc_lock);
+ }
}
diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c
index e755a7ae52c..7856bad4d99 100644
--- a/source/blender/blenlib/intern/timecode.c
+++ b/source/blender/blenlib/intern/timecode.c
@@ -94,11 +94,11 @@ size_t BLI_timecode_string_from_time(
* to cope with 'half' frames, etc., which should be fine in most cases
*/
seconds = (int)time;
- frames = iroundf((float)(((double)time - (double)seconds) * fps));
+ frames = round_fl_to_int((float)(((double)time - (double)seconds) * fps));
}
else {
/* seconds (with pixel offset rounding) */
- seconds = iroundf(time);
+ seconds = round_fl_to_int(time);
}
switch (timecode_style) {
@@ -169,7 +169,7 @@ size_t BLI_timecode_string_from_time(
/* precision of decimal part */
const int ms_dp = (power <= 0) ? (1 - power) : 1;
- const int ms = iroundf((time - (float)seconds) * 1000.0f);
+ const int ms = round_fl_to_int((time - (float)seconds) * 1000.0f);
rlen = BLI_snprintf_rlen(
str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms);
@@ -183,7 +183,7 @@ size_t BLI_timecode_string_from_time(
rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds);
}
else {
- rlen = BLI_snprintf_rlen(str, maxncpy, "%d", iroundf(time_seconds));
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
}
break;
}
@@ -250,7 +250,7 @@ size_t BLI_timecode_string_from_time_seconds(
rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds);
}
else {
- rlen = BLI_snprintf_rlen(str, maxncpy, "%d", iroundf(time_seconds));
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
}
return rlen;
diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c
index 3b06b7df09a..d6834428376 100644
--- a/source/blender/blenlib/intern/winstuff.c
+++ b/source/blender/blenlib/intern/winstuff.c
@@ -160,8 +160,6 @@ void RegisterBlendExtension(void)
GetSystemDirectory(SysDir, FILE_MAXDIR);
#ifdef _WIN64
ThumbHandlerDLL = "BlendThumb64.dll";
-#elif defined(__MINGW32__)
- ThumbHandlerDLL = "BlendThumb.dll";
#else
IsWow64Process(GetCurrentProcess(), &IsWOW64);
if (IsWOW64 == true)
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index c85cf128643..e6fc4703248 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -71,11 +71,25 @@ typedef struct BlendFileData {
BlenFileType type;
} BlendFileData;
-BlendFileData *BLO_read_from_file(const char *filepath, struct ReportList *reports);
-BlendFileData *BLO_read_from_memory(const void *mem, int memsize, struct ReportList *reports);
+
+/* skip reading some data-block types (may want to skip screen data too). */
+typedef enum eBLOReadSkip {
+ BLO_READ_SKIP_NONE = 0,
+ BLO_READ_SKIP_USERDEF = (1 << 0),
+ BLO_READ_SKIP_DATA = (1 << 1),
+} eBLOReadSkip;
+#define BLO_READ_SKIP_ALL \
+ (BLO_READ_SKIP_USERDEF | BLO_READ_SKIP_DATA)
+
+BlendFileData *BLO_read_from_file(
+ const char *filepath,
+ struct ReportList *reports, eBLOReadSkip skip_flag);
+BlendFileData *BLO_read_from_memory(
+ const void *mem, int memsize,
+ struct ReportList *reports, eBLOReadSkip skip_flag);
BlendFileData *BLO_read_from_memfile(
struct Main *oldmain, const char *filename, struct MemFile *memfile,
- struct ReportList *reports);
+ struct ReportList *reports, eBLOReadSkip skip_flag);
void BLO_blendfiledata_free(BlendFileData *bfd);
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 8cb9ef837b2..3d2e8a306de 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -69,6 +69,12 @@ if(WITH_BUILDINFO)
add_definitions(-DWITH_BUILDINFO)
endif()
+if(WITH_PYTHON)
+ if(WITH_PYTHON_SECURITY)
+ add_definitions(-DWITH_PYTHON_SECURITY)
+ endif()
+endif()
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index be893177b3b..73109413271 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -317,7 +317,9 @@ void BLO_blendhandle_close(BlendHandle *bh)
* \param reports If the return value is NULL, errors indicating the cause of the failure.
* \return The data of the file.
*/
-BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports)
+BlendFileData *BLO_read_from_file(
+ const char *filepath,
+ ReportList *reports, eBLOReadSkip skip_flags)
{
BlendFileData *bfd = NULL;
FileData *fd;
@@ -325,6 +327,7 @@ BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports)
fd = blo_openblenderfile(filepath, reports);
if (fd) {
fd->reports = reports;
+ fd->skip_flags = skip_flags;
bfd = blo_read_file_internal(fd, filepath);
blo_freefiledata(fd);
}
@@ -341,7 +344,9 @@ BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports)
* \param reports If the return value is NULL, errors indicating the cause of the failure.
* \return The data of the file.
*/
-BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *reports)
+BlendFileData *BLO_read_from_memory(
+ const void *mem, int memsize,
+ ReportList *reports, eBLOReadSkip skip_flags)
{
BlendFileData *bfd = NULL;
FileData *fd;
@@ -349,6 +354,7 @@ BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *re
fd = blo_openblendermemory(mem, memsize, reports);
if (fd) {
fd->reports = reports;
+ fd->skip_flags = skip_flags;
bfd = blo_read_file_internal(fd, "");
blo_freefiledata(fd);
}
@@ -362,7 +368,9 @@ BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *re
* \param oldmain old main, from which we will keep libraries and other datablocks that should not have changed.
* \param filename current file, only for retrieving library data.
*/
-BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFile *memfile, ReportList *reports)
+BlendFileData *BLO_read_from_memfile(
+ Main *oldmain, const char *filename, MemFile *memfile,
+ ReportList *reports, eBLOReadSkip skip_flags)
{
BlendFileData *bfd = NULL;
FileData *fd;
@@ -371,6 +379,7 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil
fd = blo_openblendermemfile(memfile, reports);
if (fd) {
fd->reports = reports;
+ fd->skip_flags = skip_flags;
BLI_strncpy(fd->relabase, filename, sizeof(fd->relabase));
/* clear ob->proxy_from pointers in old main */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 98c8a260993..3b7662be2b2 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -129,6 +129,7 @@
#include "BKE_library_idmap.h"
#include "BKE_library_query.h"
#include "BKE_idcode.h"
+#include "BKE_idprop.h"
#include "BKE_material.h"
#include "BKE_main.h" // for Main
#include "BKE_mesh.h" // for ME_ defines (patching)
@@ -531,6 +532,8 @@ void blo_split_main(ListBase *mainlist, Main *main)
for (Library *lib = main->library.first; lib; lib = lib->id.next, i++) {
Main *libmain = BKE_main_new();
libmain->curlib = lib;
+ libmain->versionfile = lib->versionfile;
+ libmain->subversionfile = lib->subversionfile;
BLI_addtail(mainlist, libmain);
lib->temp_index = i;
lib_main_array[i] = libmain;
@@ -562,6 +565,10 @@ static void read_file_version(FileData *fd, Main *main)
break;
}
}
+ if (main->curlib) {
+ main->curlib->versionfile = main->versionfile;
+ main->curlib->subversionfile = main->subversionfile;
+ }
}
#ifdef USE_GHASH_BHEAD
@@ -631,7 +638,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
/* Add library datablock itself to 'main' Main, since libraries are **never** linked data.
* Fixes bug where you could end with all ID_LI datablocks having the same name... */
- lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib");
+ lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib", 0);
lib->id.us = ID_FAKE_USERS(lib); /* Important, consistency with main ID reading code from read_libblock(). */
BLI_strncpy(lib->name, filepath, sizeof(lib->name));
BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath));
@@ -1995,7 +2002,7 @@ static void test_pointer_array(FileData *fd, void **mat)
/* ************ READ ID Properties *************** */
static void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, FileData *fd);
-static void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, FileData *fd);
+static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd);
static void IDP_DirectLinkIDPArray(IDProperty *prop, int switch_endian, FileData *fd)
{
@@ -2100,8 +2107,19 @@ static void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, FileData
BLI_endian_switch_int32(&prop->data.val2);
BLI_endian_switch_int64((int64_t *)&prop->data.val);
}
-
break;
+ case IDP_INT:
+ case IDP_FLOAT:
+ case IDP_ID:
+ break; /* Nothing special to do here. */
+ default:
+ /* Unknown IDP type, nuke it (we cannot handle unknown types everywhere in code,
+ * IDP are way too polymorphic to do it safely. */
+ printf("%s: found unknown IDProperty type %d, reset to Integer one !\n", __func__, prop->type);
+ /* Note: we do not attempt to free unknown prop, we have no way to know how to do that! */
+ prop->type = IDP_INT;
+ prop->subtype = 0;
+ IDP_Int(prop) = 0;
}
}
@@ -2126,10 +2144,39 @@ static void _IDP_DirectLinkGroup_OrFree(IDProperty **prop, int switch_endian, Fi
}
}
-/* stub function */
-static void IDP_LibLinkProperty(IDProperty *UNUSED(prop), int UNUSED(switch_endian), FileData *UNUSED(fd))
+static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd)
{
- /* Should we do something here, prop should be ensured to be non-NULL first... */
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_ID: /* PointerProperty */
+ {
+ void *newaddr = newlibadr_us(fd, NULL, IDP_Id(prop));
+ if (IDP_Id(prop) && !newaddr && G.debug) {
+ printf("Error while loading \"%s\". Data not found in file!\n", prop->name);
+ }
+ prop->data.pointer = newaddr;
+ break;
+ }
+ case IDP_IDPARRAY: /* CollectionProperty */
+ {
+ IDProperty *idp_array = IDP_IDPArray(prop);
+ for (int i = 0; i < prop->len; i++) {
+ IDP_LibLinkProperty(&(idp_array[i]), fd);
+ }
+ break;
+ }
+ case IDP_GROUP: /* PointerProperty */
+ {
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ IDP_LibLinkProperty(loop, fd);
+ }
+ break;
+ }
+ default:
+ break; /* Nothing to do for other IDProps. */
+ }
}
/* ************ READ IMAGE PREVIEW *************** */
@@ -2186,19 +2233,19 @@ static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap)
/* library brush linking after fileread */
static void lib_link_brush(FileData *fd, Main *main)
{
- Brush *brush;
-
/* only link ID pointers */
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (Brush *brush = main->brush.first; brush; brush = brush->id.next) {
if (brush->id.tag & LIB_TAG_NEED_LINK) {
- brush->id.tag &= ~LIB_TAG_NEED_LINK;
-
+ IDP_LibLinkProperty(brush->id.properties, fd);
+
/* 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(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);
+
+ brush->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -2221,13 +2268,13 @@ static void direct_link_brush(FileData *fd, Brush *brush)
}
/* ************ READ Palette *************** */
-static void lib_link_palette(FileData *UNUSED(fd), Main *main)
+static void lib_link_palette(FileData *fd, Main *main)
{
- Palette *palette;
-
/* only link ID pointers */
- for (palette = main->palettes.first; palette; palette = palette->id.next) {
+ for (Palette *palette = main->palettes.first; palette; palette = palette->id.next) {
if (palette->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(palette->id.properties, fd);
+
palette->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -2239,13 +2286,13 @@ static void direct_link_palette(FileData *fd, Palette *palette)
link_list(fd, &palette->colors);
}
-static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main)
+static void lib_link_paint_curve(FileData *fd, Main *main)
{
- PaintCurve *pc;
-
/* only link ID pointers */
- for (pc = main->paintcurves.first; pc; pc = pc->id.next) {
+ for (PaintCurve *pc = main->paintcurves.first; pc; pc = pc->id.next) {
if (pc->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(pc->id.properties, fd);
+
pc->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -2497,15 +2544,12 @@ static void direct_link_fcurves(FileData *fd, ListBase *list)
static void lib_link_action(FileData *fd, Main *main)
{
- bAction *act;
- bActionChannel *chan;
-
- for (act = main->action.first; act; act = act->id.next) {
+ for (bAction *act = main->action.first; act; act = act->id.next) {
if (act->id.tag & LIB_TAG_NEED_LINK) {
- act->id.tag &= ~LIB_TAG_NEED_LINK;
+ IDP_LibLinkProperty(act->id.properties, fd);
// XXX deprecated - old animation system <<<
- for (chan=act->chanbase.first; chan; chan=chan->next) {
+ for (bActionChannel *chan = act->chanbase.first; chan; chan = chan->next) {
chan->ipo = newlibadr_us(fd, act->id.lib, chan->ipo);
lib_link_constraint_channels(fd, &act->id, &chan->constraintChannels);
}
@@ -2518,6 +2562,8 @@ static void lib_link_action(FileData *fd, Main *main)
marker->camera = newlibadr(fd, act->id.lib, marker->camera);
}
}
+
+ act->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -2704,26 +2750,20 @@ static void direct_link_animdata(FileData *fd, AnimData *adt)
static void lib_link_cachefiles(FileData *fd, Main *bmain)
{
- CacheFile *cache_file;
-
/* only link ID pointers */
- for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
+ for (CacheFile *cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
if (cache_file->id.tag & LIB_TAG_NEED_LINK) {
- cache_file->id.tag &= ~LIB_TAG_NEED_LINK;
- }
-
- BLI_listbase_clear(&cache_file->object_paths);
- cache_file->handle = NULL;
- cache_file->handle_mutex = NULL;
-
- if (cache_file->adt) {
+ IDP_LibLinkProperty(cache_file->id.properties, fd);
lib_link_animdata(fd, &cache_file->id, cache_file->adt);
+
+ cache_file->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
{
+ BLI_listbase_clear(&cache_file->object_paths);
cache_file->handle = NULL;
cache_file->handle_mutex = NULL;
@@ -2747,19 +2787,13 @@ static void direct_link_motionpath(FileData *fd, bMotionPath *mpath)
/* ************ READ NODE TREE *************** */
-static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock)
-{
- /* Link ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
-}
-
/* Single node tree (also used for material/scene trees), ntree is not NULL */
static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
{
bNode *node;
bNodeSocket *sock;
+ IDP_LibLinkProperty(ntree->id.properties, fd);
lib_link_animdata(fd, &ntree->id, ntree->adt);
ntree->gpd = newlibadr_us(fd, id->lib, ntree->gpd);
@@ -2767,32 +2801,35 @@ static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = node->next) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(node->prop, fd);
- node->id= newlibadr_us(fd, id->lib, node->id);
+ node->id = newlibadr_us(fd, id->lib, node->id);
- for (sock = node->inputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
- for (sock = node->outputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
}
- for (sock = ntree->inputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
- for (sock = ntree->outputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
+ for (sock = ntree->inputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
+ for (sock = ntree->outputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
}
/* library ntree linking after fileread */
static void lib_link_nodetree(FileData *fd, Main *main)
{
- bNodeTree *ntree;
-
/* only link ID pointers */
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
+ for (bNodeTree *ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
if (ntree->id.tag & LIB_TAG_NEED_LINK) {
- ntree->id.tag &= ~LIB_TAG_NEED_LINK;
lib_link_ntree(fd, &ntree->id, ntree);
+
+ ntree->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3083,7 +3120,7 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
else if (ntree->type==NTREE_COMPOSIT) {
if (ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
direct_link_curvemapping(fd, node->storage);
- else if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
+ else if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
((ImageUser *)node->storage)->ok = 1;
}
else if ( ntree->type==NTREE_TEXTURE) {
@@ -3238,6 +3275,11 @@ static void direct_link_constraints(FileData *fd, ListBase *lb)
con->flag |= CONSTRAINT_SPACEONCE;
break;
}
+ case CONSTRAINT_TYPE_TRANSFORM_CACHE:
+ {
+ bTransformCacheConstraint *data = con->data;
+ data->reader = NULL;
+ }
}
}
}
@@ -3280,6 +3322,8 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name);
+ IDP_LibLinkProperty(pchan->prop, fd);
+
pchan->custom = newlibadr_us(fd, arm->id.lib, pchan->custom);
if (UNLIKELY(pchan->bone == NULL)) {
rebuild = true;
@@ -3300,13 +3344,26 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
}
}
+static void lib_link_bones(FileData *fd, Bone *bone)
+{
+ IDP_LibLinkProperty(bone->prop, fd);
+
+ for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) {
+ lib_link_bones(fd, curbone);
+ }
+}
+
static void lib_link_armature(FileData *fd, Main *main)
{
- bArmature *arm;
-
- for (arm = main->armature.first; arm; arm = arm->id.next) {
+ for (bArmature *arm = main->armature.first; arm; arm = arm->id.next) {
if (arm->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(arm->id.properties, fd);
lib_link_animdata(fd, &arm->id, arm->adt);
+
+ for (Bone *curbone = arm->bonebase.first; curbone; curbone = curbone->next) {
+ lib_link_bones(fd, curbone);
+ }
+
arm->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -3351,14 +3408,13 @@ static void direct_link_armature(FileData *fd, bArmature *arm)
static void lib_link_camera(FileData *fd, Main *main)
{
- Camera *ca;
-
- for (ca = main->camera.first; ca; ca = ca->id.next) {
+ for (Camera *ca = main->camera.first; ca; ca = ca->id.next) {
if (ca->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(ca->id.properties, fd);
lib_link_animdata(fd, &ca->id, ca->adt);
ca->ipo = newlibadr_us(fd, ca->id.lib, ca->ipo); // XXX deprecated - old animation system
-
+
ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob);
ca->id.tag &= ~LIB_TAG_NEED_LINK;
@@ -3377,16 +3433,13 @@ static void direct_link_camera(FileData *fd, Camera *ca)
static void lib_link_lamp(FileData *fd, Main *main)
{
- Lamp *la;
- MTex *mtex;
- int a;
-
- for (la = main->lamp.first; la; la = la->id.next) {
+ for (Lamp *la = main->lamp.first; la; la = la->id.next) {
if (la->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(la->id.properties, fd);
lib_link_animdata(fd, &la->id, la->adt);
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = la->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = la->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, la->id.lib, mtex->tex);
mtex->object = newlibadr(fd, la->id.lib, mtex->object);
@@ -3443,17 +3496,11 @@ void blo_do_versions_key_uidgen(Key *key)
static void lib_link_key(FileData *fd, Main *main)
{
- Key *key;
-
- for (key = main->key.first; key; key = key->id.next) {
- /*check if we need to generate unique ids for the shapekeys*/
- if (!key->uidgen) {
- blo_do_versions_key_uidgen(key);
- }
-
+ for (Key *key = main->key.first; key; key = key->id.next) {
BLI_assert((key->id.tag & LIB_TAG_EXTERN) == 0);
if (key->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(key->id.properties, fd);
lib_link_animdata(fd, &key->id, key->adt);
key->ipo = newlibadr_us(fd, key->id.lib, key->ipo); // XXX deprecated - old animation system
@@ -3516,15 +3563,14 @@ static void direct_link_key(FileData *fd, Key *key)
static void lib_link_mball(FileData *fd, Main *main)
{
- MetaBall *mb;
- int a;
-
- for (mb = main->mball.first; mb; mb = mb->id.next) {
+ for (MetaBall *mb = main->mball.first; mb; mb = mb->id.next) {
if (mb->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(mb->id.properties, fd);
lib_link_animdata(fd, &mb->id, mb->adt);
- for (a = 0; a < mb->totcol; a++)
+ for (int a = 0; a < mb->totcol; a++) {
mb->mat[a] = newlibadr_us(fd, mb->id.lib, mb->mat[a]);
+ }
mb->ipo = newlibadr_us(fd, mb->id.lib, mb->ipo); // XXX deprecated - old animation system
@@ -3553,18 +3599,15 @@ static void direct_link_mball(FileData *fd, MetaBall *mb)
static void lib_link_world(FileData *fd, Main *main)
{
- World *wrld;
- MTex *mtex;
- int a;
-
- for (wrld = main->world.first; wrld; wrld = wrld->id.next) {
+ for (World *wrld = main->world.first; wrld; wrld = wrld->id.next) {
if (wrld->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(wrld->id.properties, fd);
lib_link_animdata(fd, &wrld->id, wrld->adt);
wrld->ipo = newlibadr_us(fd, wrld->id.lib, wrld->ipo); // XXX deprecated - old animation system
- for (a=0; a < MAX_MTEX; a++) {
- mtex = wrld->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = wrld->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, wrld->id.lib, mtex->tex);
mtex->object = newlibadr(fd, wrld->id.lib, mtex->object);
@@ -3605,12 +3648,12 @@ static void direct_link_world(FileData *fd, World *wrld)
/* ************ READ VFONT ***************** */
-static void lib_link_vfont(FileData *UNUSED(fd), Main *main)
+static void lib_link_vfont(FileData *fd, Main *main)
{
- VFont *vf;
-
- for (vf = main->vfont.first; vf; vf = vf->id.next) {
+ for (VFont *vf = main->vfont.first; vf; vf = vf->id.next) {
if (vf->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(vf->id.properties, fd);
+
vf->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -3625,12 +3668,12 @@ static void direct_link_vfont(FileData *fd, VFont *vf)
/* ************ READ TEXT ****************** */
-static void lib_link_text(FileData *UNUSED(fd), Main *main)
+static void lib_link_text(FileData *fd, Main *main)
{
- Text *text;
-
- for (text = main->text.first; text; text = text->id.next) {
+ for (Text *text = main->text.first; text; text = text->id.next) {
if (text->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(text->id.properties, fd);
+
text->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -3679,11 +3722,9 @@ static void direct_link_text(FileData *fd, Text *text)
static void lib_link_image(FileData *fd, Main *main)
{
- Image *ima;
-
- for (ima = main->image.first; ima; ima = ima->id.next) {
+ for (Image *ima = main->image.first; ima; ima = ima->id.next) {
if (ima->id.tag & LIB_TAG_NEED_LINK) {
- IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(ima->id.properties, fd);
ima->id.tag &= ~LIB_TAG_NEED_LINK;
}
@@ -3748,15 +3789,14 @@ static void direct_link_image(FileData *fd, Image *ima)
static void lib_link_curve(FileData *fd, Main *main)
{
- Curve *cu;
- int a;
-
- for (cu = main->curve.first; cu; cu = cu->id.next) {
+ for (Curve *cu = main->curve.first; cu; cu = cu->id.next) {
if (cu->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(cu->id.properties, fd);
lib_link_animdata(fd, &cu->id, cu->adt);
- for (a = 0; a < cu->totcol; a++)
+ for (int a = 0; a < cu->totcol; a++) {
cu->mat[a] = newlibadr_us(fd, cu->id.lib, cu->mat[a]);
+ }
cu->bevobj = newlibadr(fd, cu->id.lib, cu->bevobj);
cu->taperobj = newlibadr(fd, cu->id.lib, cu->taperobj);
@@ -3841,10 +3881,9 @@ static void direct_link_curve(FileData *fd, Curve *cu)
static void lib_link_texture(FileData *fd, Main *main)
{
- Tex *tex;
-
- for (tex = main->tex.first; tex; tex = tex->id.next) {
+ for (Tex *tex = main->tex.first; tex; tex = tex->id.next) {
if (tex->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(tex->id.properties, fd);
lib_link_animdata(fd, &tex->id, tex->adt);
tex->ima = newlibadr_us(fd, tex->id.lib, tex->ima);
@@ -3920,23 +3959,20 @@ static void direct_link_texture(FileData *fd, Tex *tex)
static void lib_link_material(FileData *fd, Main *main)
{
- Material *ma;
- MTex *mtex;
- int a;
-
- for (ma = main->mat.first; ma; ma = ma->id.next) {
+ for (Material *ma = main->mat.first; ma; ma = ma->id.next) {
if (ma->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(ma->id.properties, fd);
lib_link_animdata(fd, &ma->id, ma->adt);
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(ma->id.properties, fd);
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++) {
- mtex = ma->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = ma->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, ma->id.lib, mtex->tex);
mtex->object = newlibadr(fd, ma->id.lib, mtex->object);
@@ -4067,14 +4103,11 @@ static void lib_link_partdeflect(FileData *fd, ID *id, PartDeflect *pd)
static void lib_link_particlesettings(FileData *fd, Main *main)
{
- ParticleSettings *part;
- ParticleDupliWeight *dw;
- MTex *mtex;
- int a;
-
- for (part = main->particle.first; part; part = part->id.next) {
+ for (ParticleSettings *part = main->particle.first; part; part = part->id.next) {
if (part->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(part->id.properties, fd);
lib_link_animdata(fd, &part->id, part->adt);
+
part->ipo = newlibadr_us(fd, part->id.lib, part->ipo); // XXX deprecated - old animation system
part->dup_ob = newlibadr(fd, part->id.lib, part->dup_ob);
@@ -4094,6 +4127,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
}
if (part->dupliweights.first && part->dup_group) {
+ ParticleDupliWeight *dw;
int index_ok = 0;
/* check for old files without indices (all indexes 0) */
if (BLI_listbase_is_single(&part->dupliweights)) {
@@ -4158,8 +4192,8 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
}
}
- for (a = 0; a < MAX_MTEX; a++) {
- mtex= part->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex= part->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, part->id.lib, mtex->tex);
mtex->object = newlibadr(fd, part->id.lib, mtex->object);
@@ -4393,7 +4427,7 @@ static void lib_link_mesh(FileData *fd, Main *main)
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(me->id.properties, fd);
lib_link_animdata(fd, &me->id, me->adt);
/* this check added for python created meshes */
@@ -4666,10 +4700,9 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
static void lib_link_latt(FileData *fd, Main *main)
{
- Lattice *lt;
-
- for (lt = main->latt.first; lt; lt = lt->id.next) {
+ for (Lattice *lt = main->latt.first; lt; lt = lt->id.next) {
if (lt->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(lt->id.properties, fd);
lib_link_animdata(fd, &lt->id, lt->adt);
lt->ipo = newlibadr_us(fd, lt->id.lib, lt->ipo); // XXX deprecated - old animation system
@@ -4697,12 +4730,12 @@ static void direct_link_latt(FileData *fd, Lattice *lt)
/* ************ READ OBJECT ***************** */
static void lib_link_modifiers__linkModifiers(
- void *userData, Object *ob, ID **idpoin, int cd_flag)
+ void *userData, Object *ob, ID **idpoin, int cb_flag)
{
FileData *fd = userData;
*idpoin = newlibadr(fd, ob->id.lib, *idpoin);
- if (*idpoin != NULL && (cd_flag & IDWALK_USER) != 0) {
+ if (*idpoin != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
id_us_plus_no_lib(*idpoin);
}
}
@@ -4713,17 +4746,13 @@ static void lib_link_modifiers(FileData *fd, Object *ob)
static void lib_link_object(FileData *fd, Main *main)
{
- Object *ob;
- PartEff *paf;
- bSensor *sens;
- bController *cont;
- bActuator *act;
- void *poin;
- int warn=0, a;
-
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ bool warn = false;
+
+ for (Object *ob = main->object.first; ob; ob = ob->id.next) {
if (ob->id.tag & LIB_TAG_NEED_LINK) {
- IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ int a;
+
+ IDP_LibLinkProperty(ob->id.properties, fd);
lib_link_animdata(fd, &ob->id, ob->adt);
// XXX deprecated - old animation system <<<
@@ -4755,17 +4784,17 @@ static void lib_link_object(FileData *fd, Main *main)
}
ob->proxy_group = newlibadr(fd, ob->id.lib, ob->proxy_group);
- poin = ob->data;
+ void *poin = ob->data;
ob->data = newlibadr_us(fd, ob->id.lib, ob->data);
- if (ob->data==NULL && poin!=NULL) {
+ if (ob->data == NULL && poin != NULL) {
if (ob->id.lib)
printf("Can't find obdata of %s lib %s\n", ob->id.name + 2, ob->id.lib->name);
else
printf("Object %s lost data.\n", ob->id.name + 2);
ob->type = OB_EMPTY;
- warn = 1;
+ warn = true;
if (ob->pose) {
/* we can't call #BKE_pose_free() here because of library linking
@@ -4811,13 +4840,13 @@ static void lib_link_object(FileData *fd, Main *main)
lib_link_nlastrips(fd, &ob->id, &ob->nlastrips);
// >>> XXX deprecated - old animation system
- for (paf = ob->effect.first; paf; paf = paf->next) {
+ for (PartEff *paf = ob->effect.first; paf; paf = paf->next) {
if (paf->type == EFF_PARTICLE) {
paf->group = newlibadr_us(fd, ob->id.lib, paf->group);
}
}
- for (sens = ob->sensors.first; sens; sens = sens->next) {
+ for (bSensor *sens = ob->sensors.first; sens; sens = sens->next) {
for (a = 0; a < sens->totlinks; a++)
sens->links[a] = newglobadr(fd, sens->links[a]);
@@ -4828,7 +4857,7 @@ static void lib_link_object(FileData *fd, Main *main)
}
}
- for (cont = ob->controllers.first; cont; cont = cont->next) {
+ for (bController *cont = ob->controllers.first; cont; cont = cont->next) {
for (a=0; a < cont->totlinks; a++)
cont->links[a] = newglobadr(fd, cont->links[a]);
@@ -4840,86 +4869,117 @@ static void lib_link_object(FileData *fd, Main *main)
cont->totslinks = 0;
}
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_SOUND) {
- bSoundActuator *sa = act->data;
- sa->sound= newlibadr_us(fd, ob->id.lib, sa->sound);
- }
- else if (act->type == ACT_GAME) {
- /* bGameActuator *ga= act->data; */
- }
- else if (act->type == ACT_CAMERA) {
- bCameraActuator *ca = act->data;
- ca->ob= newlibadr(fd, ob->id.lib, ca->ob);
- }
- /* leave this one, it's obsolete but necessary to read for conversion */
- else if (act->type == ACT_ADD_OBJECT) {
- bAddObjectActuator *eoa = act->data;
- if (eoa) eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
- }
- else if (act->type == ACT_OBJECT) {
- bObjectActuator *oa = act->data;
- if (oa == NULL) {
- init_actuator(act);
+ for (bActuator *act = ob->actuators.first; act; act = act->next) {
+ switch (act->type) {
+ case ACT_SOUND:
+ {
+ bSoundActuator *sa = act->data;
+ sa->sound = newlibadr_us(fd, ob->id.lib, sa->sound);
+ break;
}
- else {
- oa->reference = newlibadr(fd, ob->id.lib, oa->reference);
+ case ACT_GAME:
+ /* bGameActuator *ga= act->data; */
+ break;
+ case ACT_CAMERA:
+ {
+ bCameraActuator *ca = act->data;
+ ca->ob = newlibadr(fd, ob->id.lib, ca->ob);
+ break;
}
- }
- else if (act->type == ACT_EDIT_OBJECT) {
- bEditObjectActuator *eoa = act->data;
- if (eoa == NULL) {
- init_actuator(act);
+ /* leave this one, it's obsolete but necessary to read for conversion */
+ case ACT_ADD_OBJECT:
+ {
+ bAddObjectActuator *eoa = act->data;
+ if (eoa)
+ eoa->ob = newlibadr(fd, ob->id.lib, eoa->ob);
+ break;
}
- else {
- eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
- eoa->me= newlibadr(fd, ob->id.lib, eoa->me);
+ case ACT_OBJECT:
+ {
+ bObjectActuator *oa = act->data;
+ if (oa == NULL) {
+ init_actuator(act);
+ }
+ else {
+ oa->reference = newlibadr(fd, ob->id.lib, oa->reference);
+ }
+ break;
}
- }
- else if (act->type == ACT_SCENE) {
- bSceneActuator *sa = act->data;
- sa->camera= newlibadr(fd, ob->id.lib, sa->camera);
- sa->scene= newlibadr(fd, ob->id.lib, sa->scene);
- }
- else if (act->type == ACT_ACTION) {
- bActionActuator *aa = act->data;
- aa->act= newlibadr_us(fd, ob->id.lib, aa->act);
- }
- else if (act->type == ACT_SHAPEACTION) {
- bActionActuator *aa = act->data;
- aa->act= newlibadr_us(fd, ob->id.lib, aa->act);
- }
- else if (act->type == ACT_PROPERTY) {
- bPropertyActuator *pa = act->data;
- pa->ob= newlibadr(fd, ob->id.lib, pa->ob);
- }
- else if (act->type == ACT_MESSAGE) {
- bMessageActuator *ma = act->data;
- ma->toObject= newlibadr(fd, ob->id.lib, ma->toObject);
- }
- else if (act->type == ACT_2DFILTER) {
- bTwoDFilterActuator *_2dfa = act->data;
- _2dfa->text= newlibadr(fd, ob->id.lib, _2dfa->text);
- }
- else if (act->type == ACT_PARENT) {
- bParentActuator *parenta = act->data;
- parenta->ob = newlibadr(fd, ob->id.lib, parenta->ob);
- }
- else if (act->type == ACT_STATE) {
- /* bStateActuator *statea = act->data; */
- }
- else if (act->type == ACT_ARMATURE) {
- bArmatureActuator *arma= act->data;
- arma->target= newlibadr(fd, ob->id.lib, arma->target);
- arma->subtarget= newlibadr(fd, ob->id.lib, arma->subtarget);
- }
- else if (act->type == ACT_STEERING) {
- bSteeringActuator *steeringa = act->data;
- steeringa->target = newlibadr(fd, ob->id.lib, steeringa->target);
- steeringa->navmesh = newlibadr(fd, ob->id.lib, steeringa->navmesh);
- }
- else if (act->type == ACT_MOUSE) {
- /* bMouseActuator *moa= act->data; */
+ case ACT_EDIT_OBJECT:
+ {
+ bEditObjectActuator *eoa = act->data;
+ if (eoa == NULL) {
+ init_actuator(act);
+ }
+ else {
+ eoa->ob = newlibadr(fd, ob->id.lib, eoa->ob);
+ eoa->me = newlibadr(fd, ob->id.lib, eoa->me);
+ }
+ break;
+ }
+ case ACT_SCENE:
+ {
+ bSceneActuator *sa = act->data;
+ sa->camera = newlibadr(fd, ob->id.lib, sa->camera);
+ sa->scene = newlibadr(fd, ob->id.lib, sa->scene);
+ break;
+ }
+ case ACT_ACTION:
+ {
+ bActionActuator *aa = act->data;
+ aa->act = newlibadr_us(fd, ob->id.lib, aa->act);
+ break;
+ }
+ case ACT_SHAPEACTION:
+ {
+ bActionActuator *aa = act->data;
+ aa->act = newlibadr_us(fd, ob->id.lib, aa->act);
+ break;
+ }
+ case ACT_PROPERTY:
+ {
+ bPropertyActuator *pa = act->data;
+ pa->ob = newlibadr(fd, ob->id.lib, pa->ob);
+ break;
+ }
+ case ACT_MESSAGE:
+ {
+ bMessageActuator *ma = act->data;
+ ma->toObject = newlibadr(fd, ob->id.lib, ma->toObject);
+ break;
+ }
+ case ACT_2DFILTER:
+ {
+ bTwoDFilterActuator *_2dfa = act->data;
+ _2dfa->text = newlibadr(fd, ob->id.lib, _2dfa->text);
+ break;
+ }
+ case ACT_PARENT:
+ {
+ bParentActuator *parenta = act->data;
+ parenta->ob = newlibadr(fd, ob->id.lib, parenta->ob);
+ break;
+ }
+ case ACT_STATE:
+ /* bStateActuator *statea = act->data; */
+ break;
+ case ACT_ARMATURE:
+ {
+ bArmatureActuator *arma= act->data;
+ arma->target = newlibadr(fd, ob->id.lib, arma->target);
+ arma->subtarget = newlibadr(fd, ob->id.lib, arma->subtarget);
+ break;
+ }
+ case ACT_STEERING:
+ {
+ bSteeringActuator *steeringa = act->data;
+ steeringa->target = newlibadr(fd, ob->id.lib, steeringa->target);
+ steeringa->navmesh = newlibadr(fd, ob->id.lib, steeringa->navmesh);
+ break;
+ }
+ case ACT_MOUSE:
+ /* bMouseActuator *moa = act->data; */
+ break;
}
}
@@ -5302,6 +5362,41 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
csmd->delta_cache = NULL;
csmd->delta_cache_num = 0;
}
+ else if (md->type == eModifierType_MeshSequenceCache) {
+ MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
+ msmcd->reader = NULL;
+ }
+ else if (md->type == eModifierType_SurfaceDeform) {
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+
+ smd->verts = newdataadr(fd, smd->verts);
+
+ if (smd->verts) {
+ for (int i = 0; i < smd->numverts; i++) {
+ smd->verts[i].binds = newdataadr(fd, smd->verts[i].binds);
+
+ if (smd->verts[i].binds) {
+ for (int j = 0; j < smd->verts[i].numbinds; j++) {
+ smd->verts[i].binds[j].vert_inds = newdataadr(fd, smd->verts[i].binds[j].vert_inds);
+ smd->verts[i].binds[j].vert_weights = newdataadr(fd, smd->verts[i].binds[j].vert_weights);
+
+ if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ if (smd->verts[i].binds[j].vert_inds)
+ BLI_endian_switch_uint32_array(smd->verts[i].binds[j].vert_inds, smd->verts[i].binds[j].numverts);
+
+ if (smd->verts[i].binds[j].vert_weights) {
+ if (smd->verts[i].binds[j].mode == MOD_SDEF_MODE_CENTROID ||
+ smd->verts[i].binds[j].mode == MOD_SDEF_MODE_LOOPTRI)
+ BLI_endian_switch_float_array(smd->verts[i].binds[j].vert_weights, 3);
+ else
+ BLI_endian_switch_float_array(smd->verts[i].binds[j].vert_weights, smd->verts[i].binds[j].numverts);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
}
@@ -5616,23 +5711,16 @@ static bool scene_validate_setscene__liblink(Scene *sce, const int totscene)
static void lib_link_scene(FileData *fd, Main *main)
{
- Scene *sce;
- Base *base, *next;
- Sequence *seq;
- SceneRenderLayer *srl;
- FreestyleModuleConfig *fmc;
- FreestyleLineSet *fls;
-
#ifdef USE_SETSCENE_CHECK
bool need_check_set = false;
int totscene = 0;
#endif
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (Scene *sce = main->scene.first; sce; sce = sce->id.next) {
if (sce->id.tag & LIB_TAG_NEED_LINK) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(sce->id.properties, fd);
lib_link_animdata(fd, &sce->id, sce->adt);
lib_link_keyingsets(fd, &sce->id, &sce->keyingsets);
@@ -5668,7 +5756,7 @@ static void lib_link_scene(FileData *fd, Main *main)
sce->toolsettings->particle.shape_object = newlibadr(fd, sce->id.lib, sce->toolsettings->particle.shape_object);
- for (base = sce->base.first; base; base = next) {
+ for (Base *next, *base = sce->base.first; base; base = next) {
next = base->next;
base->object = newlibadr_us(fd, sce->id.lib, base->object);
@@ -5682,8 +5770,11 @@ static void lib_link_scene(FileData *fd, Main *main)
}
}
+ Sequence *seq;
SEQ_BEGIN (sce->ed, seq)
{
+ IDP_LibLinkProperty(seq->prop, fd);
+
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) {
@@ -5747,13 +5838,13 @@ static void lib_link_scene(FileData *fd, Main *main)
composite_patch(sce->nodetree, sce);
}
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ for (SceneRenderLayer *srl = sce->r.layers.first; srl; srl = srl->next) {
srl->mat_override = newlibadr_us(fd, sce->id.lib, srl->mat_override);
srl->light_override = newlibadr_us(fd, sce->id.lib, srl->light_override);
- for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
+ for (FreestyleModuleConfig *fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
fmc->script = newlibadr(fd, sce->id.lib, fmc->script);
}
- for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
+ for (FreestyleLineSet *fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
fls->linestyle = newlibadr_us(fd, sce->id.lib, fls->linestyle);
fls->group = newlibadr_us(fd, sce->id.lib, fls->group);
}
@@ -5787,7 +5878,7 @@ static void lib_link_scene(FileData *fd, Main *main)
#ifdef USE_SETSCENE_CHECK
if (need_check_set) {
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (Scene *sce = main->scene.first; sce; sce = sce->id.next) {
if (sce->id.tag & LIB_TAG_NEED_LINK) {
sce->id.tag &= ~LIB_TAG_NEED_LINK;
if (!scene_validate_setscene__liblink(sce, totscene)) {
@@ -5912,16 +6003,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->toolsettings->particle.scene = NULL;
sce->toolsettings->particle.object = NULL;
sce->toolsettings->gp_sculpt.paintcursor = NULL;
-
- /* in rare cases this is needed, see [#33806] */
- if (sce->toolsettings->vpaint) {
- sce->toolsettings->vpaint->vpaint_prev = NULL;
- sce->toolsettings->vpaint->tot = 0;
- }
- if (sce->toolsettings->wpaint) {
- sce->toolsettings->wpaint->wpaint_prev = NULL;
- sce->toolsettings->wpaint->tot = 0;
- }
+
/* relink grease pencil drawing brushes */
link_list(fd, &sce->toolsettings->gp_brushes);
for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
@@ -5938,6 +6020,12 @@ static void direct_link_scene(FileData *fd, Scene *sce)
direct_link_curvemapping(fd, brush->cur_jitter);
}
}
+
+ /* relink grease pencil interpolation curves */
+ sce->toolsettings->gp_interpolate.custom_ipo = newdataadr(fd, sce->toolsettings->gp_interpolate.custom_ipo);
+ if (sce->toolsettings->gp_interpolate.custom_ipo) {
+ direct_link_curvemapping(fd, sce->toolsettings->gp_interpolate.custom_ipo);
+ }
}
if (sce->ed) {
@@ -5998,9 +6086,13 @@ static void direct_link_scene(FileData *fd, Scene *sce)
seq->strip->transform = NULL;
}
if (seq->flag & SEQ_USE_PROXY) {
- seq->strip->proxy = newdataadr(
- fd, seq->strip->proxy);
- seq->strip->proxy->anim = NULL;
+ seq->strip->proxy = newdataadr(fd, seq->strip->proxy);
+ if (seq->strip->proxy) {
+ seq->strip->proxy->anim = NULL;
+ }
+ else {
+ BKE_sequencer_proxy_set(seq, true);
+ }
}
else {
seq->strip->proxy = NULL;
@@ -6060,11 +6152,6 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->r.avicodecdata->lpFormat = newdataadr(fd, sce->r.avicodecdata->lpFormat);
sce->r.avicodecdata->lpParms = newdataadr(fd, sce->r.avicodecdata->lpParms);
}
-
- sce->r.qtcodecdata = newdataadr(fd, sce->r.qtcodecdata);
- if (sce->r.qtcodecdata) {
- sce->r.qtcodecdata->cdParms = newdataadr(fd, sce->r.qtcodecdata->cdParms);
- }
if (sce->r.ffcodecdata.properties) {
sce->r.ffcodecdata.properties = newdataadr(fd, sce->r.ffcodecdata.properties);
IDP_DirectLinkGroup_OrFree(&sce->r.ffcodecdata.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
@@ -6075,6 +6162,11 @@ static void direct_link_scene(FileData *fd, Scene *sce)
link_list(fd, &(sce->r.layers));
link_list(fd, &(sce->r.views));
+
+ for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ srl->prop = newdataadr(fd, srl->prop);
+ IDP_DirectLinkGroup_OrFree(&srl->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
for (srl = sce->r.layers.first; srl; srl = srl->next) {
link_list(fd, &(srl->freestyleConfig.modules));
}
@@ -6190,8 +6282,10 @@ static void lib_link_windowmanager(FileData *fd, Main *main)
for (wm = main->wm.first; wm; wm = wm->id.next) {
if (wm->id.tag & LIB_TAG_NEED_LINK) {
- for (win = wm->windows.first; win; win = win->next)
+ /* Note: WM IDProperties are never written to file, hence no need to read/link them here. */
+ for (win = wm->windows.first; win; win = win->next) {
win->screen = newlibadr(fd, NULL, win->screen);
+ }
wm->id.tag &= ~LIB_TAG_NEED_LINK;
}
@@ -6203,13 +6297,12 @@ static void lib_link_windowmanager(FileData *fd, Main *main)
/* relink's grease pencil data's refs */
static void lib_link_gpencil(FileData *fd, Main *main)
{
- bGPdata *gpd;
-
- for (gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
if (gpd->id.tag & LIB_TAG_NEED_LINK) {
- gpd->id.tag &= ~LIB_TAG_NEED_LINK;
-
+ IDP_LibLinkProperty(gpd->id.properties, fd);
lib_link_animdata(fd, &gpd->id, gpd->adt);
+
+ gpd->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -6271,12 +6364,11 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
* check lib pointers in call below */
static void lib_link_screen(FileData *fd, Main *main)
{
- bScreen *sc;
- ScrArea *sa;
-
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) {
if (sc->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(sc->id.properties, fd);
id_us_ensure_real(&sc->id);
+
sc->scene = newlibadr(fd, sc->id.lib, sc->scene);
/* this should not happen, but apparently it does somehow. Until we figure out the cause,
@@ -6287,177 +6379,204 @@ static void lib_link_screen(FileData *fd, Main *main)
sc->animtimer = NULL; /* saved in rare cases */
sc->scrubbing = false;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
-
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
sa->full = newlibadr(fd, sc->id.lib, sa->full);
- for (sl = sa->spacedata.first; sl; sl= sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D*) sl;
- BGpic *bgpic = NULL;
-
- v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera);
- v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre);
-
- /* should be do_versions but not easy adding into the listbase */
- if (v3d->bgpic) {
- v3d->bgpic = newlibadr(fd, sc->id.lib, v3d->bgpic);
- BLI_addtail(&v3d->bgpicbase, bgpic);
- v3d->bgpic = NULL;
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl= sl->next) {
+ switch (sl->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d = (View3D*) sl;
+ BGpic *bgpic = NULL;
+
+ v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera);
+ v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre);
+
+ /* should be do_versions but not easy adding into the listbase */
+ if (v3d->bgpic) {
+ v3d->bgpic = newlibadr(fd, sc->id.lib, v3d->bgpic);
+ BLI_addtail(&v3d->bgpicbase, bgpic);
+ v3d->bgpic = NULL;
+ }
+
+ for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ bgpic->ima = newlibadr_us(fd, sc->id.lib, bgpic->ima);
+ bgpic->clip = newlibadr_us(fd, sc->id.lib, bgpic->clip);
+ }
+ if (v3d->localvd) {
+ v3d->localvd->camera = newlibadr(fd, sc->id.lib, v3d->localvd->camera);
+ }
+ break;
}
-
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- bgpic->ima = newlibadr_us(fd, sc->id.lib, bgpic->ima);
- bgpic->clip = newlibadr_us(fd, sc->id.lib, bgpic->clip);
+ case SPACE_IPO:
+ {
+ SpaceIpo *sipo = (SpaceIpo *)sl;
+ bDopeSheet *ads = sipo->ads;
+
+ if (ads) {
+ ads->source = newlibadr(fd, sc->id.lib, ads->source);
+ ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ }
+ break;
}
- if (v3d->localvd) {
- v3d->localvd->camera = newlibadr(fd, sc->id.lib, v3d->localvd->camera);
+ case SPACE_BUTS:
+ {
+ SpaceButs *sbuts = (SpaceButs *)sl;
+ sbuts->pinid = newlibadr(fd, sc->id.lib, sbuts->pinid);
+ if (sbuts->pinid == NULL) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
+ break;
}
- }
- else if (sl->spacetype == SPACE_IPO) {
- SpaceIpo *sipo = (SpaceIpo *)sl;
- bDopeSheet *ads = sipo->ads;
-
- if (ads) {
- ads->source = newlibadr(fd, sc->id.lib, ads->source);
- ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ case SPACE_FILE:
+ break;
+ case SPACE_ACTION:
+ {
+ SpaceAction *saction = (SpaceAction *)sl;
+ bDopeSheet *ads = &saction->ads;
+
+ if (ads) {
+ ads->source = newlibadr(fd, sc->id.lib, ads->source);
+ ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ }
+
+ saction->action = newlibadr(fd, sc->id.lib, saction->action);
+ break;
}
- }
- else if (sl->spacetype == SPACE_BUTS) {
- SpaceButs *sbuts = (SpaceButs *)sl;
- sbuts->pinid = newlibadr(fd, sc->id.lib, sbuts->pinid);
- if (sbuts->pinid == NULL) {
- sbuts->flag &= ~SB_PIN_CONTEXT;
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ 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!
+ */
+ sima->gpd = newlibadr_us(fd, sc->id.lib, sima->gpd);
+ break;
}
- }
- else if (sl->spacetype == SPACE_FILE) {
- ;
- }
- else if (sl->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)sl;
- bDopeSheet *ads = &saction->ads;
-
- if (ads) {
- ads->source = newlibadr(fd, sc->id.lib, ads->source);
- ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+
+ /* 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!
+ */
+ sseq->gpd = newlibadr_us(fd, sc->id.lib, sseq->gpd);
+ break;
}
-
- saction->action = newlibadr(fd, sc->id.lib, saction->action);
- }
- else if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
-
- 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!
- */
- sima->gpd = newlibadr_us(fd, sc->id.lib, sima->gpd);
- }
- else if (sl->spacetype == SPACE_SEQ) {
- SpaceSeq *sseq = (SpaceSeq *)sl;
-
- /* 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!
- */
- sseq->gpd = newlibadr_us(fd, sc->id.lib, sseq->gpd);
+ case SPACE_NLA:
+ {
+ SpaceNla *snla= (SpaceNla *)sl;
+ bDopeSheet *ads= snla->ads;
+
+ if (ads) {
+ ads->source = newlibadr(fd, sc->id.lib, ads->source);
+ ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ }
+ break;
+ }
+ case SPACE_TEXT:
+ {
+ SpaceText *st= (SpaceText *)sl;
- }
- else if (sl->spacetype == SPACE_NLA) {
- SpaceNla *snla= (SpaceNla *)sl;
- bDopeSheet *ads= snla->ads;
-
- if (ads) {
- ads->source = newlibadr(fd, sc->id.lib, ads->source);
- ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ st->text= newlibadr(fd, sc->id.lib, st->text);
+ break;
}
- }
- else if (sl->spacetype == SPACE_TEXT) {
- SpaceText *st= (SpaceText *)sl;
-
- st->text= newlibadr(fd, sc->id.lib, st->text);
- }
- else if (sl->spacetype == SPACE_SCRIPT) {
- SpaceScript *scpt = (SpaceScript *)sl;
- /*scpt->script = NULL; - 2.45 set to null, better re-run the script */
- if (scpt->script) {
- scpt->script = newlibadr(fd, sc->id.lib, scpt->script);
+ case SPACE_SCRIPT:
+ {
+ SpaceScript *scpt = (SpaceScript *)sl;
+ /*scpt->script = NULL; - 2.45 set to null, better re-run the script */
if (scpt->script) {
- SCRIPT_SET_NULL(scpt->script);
+ scpt->script = newlibadr(fd, sc->id.lib, scpt->script);
+ if (scpt->script) {
+ SCRIPT_SET_NULL(scpt->script);
+ }
}
+ break;
}
- }
- else if (sl->spacetype == SPACE_OUTLINER) {
- SpaceOops *so= (SpaceOops *)sl;
- so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id);
-
- if (so->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
+ case SPACE_OUTLINER:
+ {
+ SpaceOops *so= (SpaceOops *)sl;
+ so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id);
+
+ if (so->treestore) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ tselem->id = newlibadr(fd, NULL, tselem->id);
+ }
+ if (so->treehash) {
+ /* rebuild hash table, because it depends on ids too */
+ so->storeflag |= SO_TREESTORE_REBUILD;
+ }
+ }
+ break;
+ }
+ case SPACE_NODE:
+ {
+ SpaceNode *snode = (SpaceNode *)sl;
+ bNodeTreePath *path, *path_next;
+ bNodeTree *ntree;
+
+ /* node tree can be stored locally in id too, link this first */
+ snode->id = newlibadr(fd, sc->id.lib, snode->id);
+ snode->from = newlibadr(fd, sc->id.lib, snode->from);
+
+ ntree = snode->id ? ntreeFromID(snode->id) : NULL;
+ snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree);
+
+ for (path = snode->treepath.first; path; path = path->next) {
+ if (path == snode->treepath.first) {
+ /* first nodetree in path is same as snode->nodetree */
+ path->nodetree = snode->nodetree;
+ }
+ else
+ path->nodetree = newlibadr_us(fd, sc->id.lib, path->nodetree);
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- tselem->id = newlibadr(fd, NULL, tselem->id);
+ if (!path->nodetree)
+ break;
}
- if (so->treehash) {
- /* rebuild hash table, because it depends on ids too */
- so->storeflag |= SO_TREESTORE_REBUILD;
+
+ /* remaining path entries are invalid, remove */
+ for (; path; path = path_next) {
+ path_next = path->next;
+
+ BLI_remlink(&snode->treepath, path);
+ MEM_freeN(path);
}
- }
- }
- else if (sl->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)sl;
- bNodeTreePath *path, *path_next;
- bNodeTree *ntree;
-
- /* node tree can be stored locally in id too, link this first */
- snode->id = newlibadr(fd, sc->id.lib, snode->id);
- snode->from = newlibadr(fd, sc->id.lib, snode->from);
-
- ntree = snode->id ? ntreeFromID(snode->id) : NULL;
- snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree);
-
- for (path = snode->treepath.first; path; path = path->next) {
- if (path == snode->treepath.first) {
- /* first nodetree in path is same as snode->nodetree */
- path->nodetree = snode->nodetree;
+
+ /* edittree is just the last in the path,
+ * set this directly since the path may have been shortened above */
+ if (snode->treepath.last) {
+ path = snode->treepath.last;
+ snode->edittree = path->nodetree;
}
- else
- path->nodetree = newlibadr_us(fd, sc->id.lib, path->nodetree);
-
- if (!path->nodetree)
- break;
+ else {
+ snode->edittree = NULL;
+ }
+ break;
}
-
- /* remaining path entries are invalid, remove */
- for (; path; path = path_next) {
- path_next = path->next;
-
- BLI_remlink(&snode->treepath, path);
- MEM_freeN(path);
+ case SPACE_CLIP:
+ {
+ SpaceClip *sclip = (SpaceClip *)sl;
+
+ 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);
+ break;
}
-
- /* edittree is just the last in the path,
- * set this directly since the path may have been shortened above */
- if (snode->treepath.last) {
- path = snode->treepath.last;
- snode->edittree = path->nodetree;
+ case SPACE_LOGIC:
+ {
+ SpaceLogic *slogic = (SpaceLogic *)sl;
+
+ slogic->gpd = newlibadr_us(fd, sc->id.lib, slogic->gpd);
+ break;
}
- else
- snode->edittree = NULL;
- }
- else if (sl->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = (SpaceClip *)sl;
-
- 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;
-
- slogic->gpd = newlibadr_us(fd, sc->id.lib, slogic->gpd);
+ default:
+ break;
}
}
}
@@ -7331,13 +7450,13 @@ static void fix_relpaths_library(const char *basepath, Main *main)
static void lib_link_speaker(FileData *fd, Main *main)
{
- Speaker *spk;
-
- for (spk = main->speaker.first; spk; spk = spk->id.next) {
+ for (Speaker *spk = main->speaker.first; spk; spk = spk->id.next) {
if (spk->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(spk->id.properties, fd);
lib_link_animdata(fd, &spk->id, spk->adt);
spk->sound = newlibadr_us(fd, spk->id.lib, spk->sound);
+
spk->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -7387,14 +7506,15 @@ static void direct_link_sound(FileData *fd, bSound *sound)
static void lib_link_sound(FileData *fd, Main *main)
{
- bSound *sound;
-
- for (sound = main->sound.first; sound; sound = sound->id.next) {
+ for (bSound *sound = main->sound.first; sound; sound = sound->id.next) {
if (sound->id.tag & LIB_TAG_NEED_LINK) {
- sound->id.tag &= ~LIB_TAG_NEED_LINK;
+ IDP_LibLinkProperty(sound->id.properties, fd);
+
sound->ipo = newlibadr_us(fd, sound->id.lib, sound->ipo); // XXX deprecated - old animation system
BKE_sound_load(main, sound);
+
+ sound->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -7409,17 +7529,13 @@ static void direct_link_group(FileData *fd, Group *group)
static void lib_link_group(FileData *fd, Main *main)
{
- Group *group;
- GroupObject *go;
- bool add_us;
-
- for (group = main->group.first; group; group = group->id.next) {
+ for (Group *group = main->group.first; group; group = group->id.next) {
if (group->id.tag & LIB_TAG_NEED_LINK) {
- group->id.tag &= ~LIB_TAG_NEED_LINK;
+ IDP_LibLinkProperty(group->id.properties, fd);
- add_us = false;
+ bool add_us = false;
- for (go = group->gobject.first; go; go = go->next) {
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
go->ob = newlibadr_real_us(fd, group->id.lib, go->ob);
if (go->ob) {
go->ob->flag |= OB_FROMGROUP;
@@ -7431,6 +7547,8 @@ static void lib_link_group(FileData *fd, Main *main)
id_us_ensure_real(&group->id);
}
BKE_group_object_unlink(group, NULL, NULL, NULL); /* removes NULL entries */
+
+ group->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -7535,13 +7653,11 @@ static void lib_link_moviePlaneTracks(FileData *fd, MovieClip *clip, ListBase *t
static void lib_link_movieclip(FileData *fd, Main *main)
{
- MovieClip *clip;
-
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (MovieClip *clip = main->movieclip.first; clip; clip = clip->id.next) {
if (clip->id.tag & LIB_TAG_NEED_LINK) {
MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
+ IDP_LibLinkProperty(clip->id.properties, fd);
lib_link_animdata(fd, &clip->id, clip->adt);
clip->gpd = newlibadr_us(fd, clip->id.lib, clip->gpd);
@@ -7549,7 +7665,7 @@ static void lib_link_movieclip(FileData *fd, Main *main)
lib_link_movieTracks(fd, clip, &tracking->tracks);
lib_link_moviePlaneTracks(fd, clip, &tracking->plane_tracks);
- for (object = tracking->objects.first; object; object = object->next) {
+ for (MovieTrackingObject *object = tracking->objects.first; object; object = object->next) {
lib_link_movieTracks(fd, clip, &object->tracks);
lib_link_moviePlaneTracks(fd, clip, &object->plane_tracks);
}
@@ -7626,16 +7742,12 @@ static void lib_link_mask_parent(FileData *fd, Mask *mask, MaskParent *parent)
static void lib_link_mask(FileData *fd, Main *main)
{
- Mask *mask;
-
- mask = main->mask.first;
- while (mask) {
+ for (Mask *mask = main->mask.first; mask; mask = mask->id.next) {
if (mask->id.tag & LIB_TAG_NEED_LINK) {
- MaskLayer *masklay;
-
+ IDP_LibLinkProperty(mask->id.properties, fd);
lib_link_animdata(fd, &mask->id, mask->adt);
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ for (MaskLayer *masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
spline = masklay->splines.first;
@@ -7656,7 +7768,6 @@ static void lib_link_mask(FileData *fd, Main *main)
mask->id.tag &= ~LIB_TAG_NEED_LINK;
}
- mask = mask->id.next;
}
}
@@ -7664,18 +7775,13 @@ static void lib_link_mask(FileData *fd, Main *main)
static void lib_link_linestyle(FileData *fd, Main *main)
{
- FreestyleLineStyle *linestyle;
- LineStyleModifier *m;
- MTex *mtex;
- int a;
-
- linestyle = main->linestyle.first;
- while (linestyle) {
+ for (FreestyleLineStyle *linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) {
if (linestyle->id.tag & LIB_TAG_NEED_LINK) {
- linestyle->id.tag &= ~LIB_TAG_NEED_LINK;
+ LineStyleModifier *m;
- IDP_LibLinkProperty(linestyle->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(linestyle->id.properties, fd);
lib_link_animdata(fd, &linestyle->id, linestyle->adt);
+
for (m = linestyle->color_modifiers.first; m; m = m->next) {
switch (m->type) {
case LS_MODIFIER_DISTANCE_FROM_OBJECT:
@@ -7706,8 +7812,8 @@ static void lib_link_linestyle(FileData *fd, Main *main)
break;
}
}
- for (a=0; a < MAX_MTEX; a++) {
- mtex = linestyle->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = linestyle->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, linestyle->id.lib, mtex->tex);
mtex->object = newlibadr(fd, linestyle->id.lib, mtex->object);
@@ -7717,8 +7823,9 @@ static void lib_link_linestyle(FileData *fd, Main *main)
lib_link_ntree(fd, &linestyle->id, linestyle->nodetree);
linestyle->nodetree->id.lib = linestyle->id.lib;
}
+
+ linestyle->id.tag &= ~LIB_TAG_NEED_LINK;
}
- linestyle = linestyle->id.next;
}
}
@@ -8102,12 +8209,16 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
id->lib = main->curlib;
id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
+ id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_ID) {
return blo_nextbhead(fd, bhead);
}
-
+
+ /* That way, we know which datablock needs do_versions (required currently for linking). */
+ id->tag |= LIB_TAG_NEW;
+
/* need a name for the mallocN, just for debugging and sane prints on leaks */
allocname = dataname(GS(id->name));
@@ -8365,14 +8476,13 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
/* don't forget to set version number in BKE_blender_version.h! */
}
-#if 0 // XXX: disabled for now... we still don't have this in the right place in the loading code for it to work
-static void do_versions_after_linking(FileData *fd, Library *lib, Main *main)
+static void do_versions_after_linking(Main *main)
{
- /* old Animation System (using IPO's) needs to be converted to the new Animato system */
- if (main->versionfile < 250)
- do_versions_ipos_to_animato(main);
+// printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->name : main->name,
+// main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile);
+
+ do_versions_after_linking_270(main);
}
-#endif
static void lib_link_all(FileData *fd, Main *main)
{
@@ -8386,12 +8496,13 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_screen(fd, main);
lib_link_scene(fd, main);
lib_link_object(fd, main);
+ lib_link_mesh(fd, main);
lib_link_curve(fd, main);
lib_link_mball(fd, main);
lib_link_material(fd, main);
lib_link_texture(fd, main);
lib_link_image(fd, main);
- lib_link_ipo(fd, main); // XXX deprecated... still needs to be maintained for version patches still
+ lib_link_ipo(fd, main); /* XXX deprecated... still needs to be maintained for version patches still */
lib_link_key(fd, main);
lib_link_world(fd, main);
lib_link_lamp(fd, main);
@@ -8404,7 +8515,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_armature(fd, main);
lib_link_action(fd, main);
lib_link_vfont(fd, main);
- lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
+ lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
lib_link_brush(fd, main);
lib_link_palette(fd, main);
lib_link_paint_curve(fd, main);
@@ -8415,9 +8526,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_gpencil(fd, main);
lib_link_cachefiles(fd, main);
- lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
-
- lib_link_library(fd, main); /* only init users */
+ lib_link_library(fd, main); /* only init users */
}
static void direct_link_keymapitem(FileData *fd, wmKeyMapItem *kmi)
@@ -8541,7 +8650,12 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = read_global(bfd, fd, bhead);
break;
case USER:
- bhead = read_userdef(bfd, fd, bhead);
+ if (fd->skip_flags & BLO_READ_SKIP_USERDEF) {
+ bhead = blo_nextbhead(fd, bhead);
+ }
+ else {
+ bhead = read_userdef(bfd, fd, bhead);
+ }
break;
case ENDB:
bhead = NULL;
@@ -8550,15 +8664,25 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
case ID_ID:
/* Always adds to the most recently loaded ID_LI block, see direct_link_library.
* This is part of the file format definition. */
- bhead = read_libblock(fd, mainlist.last, bhead, LIB_TAG_READ | LIB_TAG_EXTERN, NULL);
+ if (fd->skip_flags & BLO_READ_SKIP_DATA) {
+ bhead = blo_nextbhead(fd, bhead);
+ }
+ else {
+ bhead = read_libblock(fd, mainlist.last, bhead, LIB_TAG_READ | LIB_TAG_EXTERN, NULL);
+ }
break;
-
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
case ID_SCRN:
bhead->code = ID_SCR;
- /* deliberate pass on to default */
+ /* pass on to default */
+ ATTR_FALLTHROUGH;
default:
- bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, NULL);
+ if (fd->skip_flags & BLO_READ_SKIP_DATA) {
+ bhead = blo_nextbhead(fd, bhead);
+ }
+ else {
+ bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, NULL);
+ }
}
}
@@ -8573,7 +8697,20 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
blo_join_main(&mainlist);
lib_link_all(fd, bfd->main);
- //do_versions_after_linking(fd, NULL, bfd->main); // XXX: not here (or even in this function at all)! this causes crashes on many files - Aligorith (July 04, 2010)
+
+ /* Skip in undo case. */
+ if (fd->memfile == NULL) {
+ /* Yep, second splitting... but this is a very cheap operation, so no big deal. */
+ blo_split_main(&mainlist, bfd->main);
+ for (Main *mainvar = mainlist.first; mainvar; mainvar = mainvar->next) {
+ BLI_assert(mainvar->versionfile != 0);
+ do_versions_after_linking(mainvar);
+ }
+ blo_join_main(&mainlist);
+ }
+
+ BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false);
+
lib_verify_nodetree(bfd->main, true);
fix_relpaths_library(fd->relabase, bfd->main); /* make all relative paths, relative to the open blend file */
@@ -8810,6 +8947,31 @@ static void expand_constraint_channels(FileData *fd, Main *mainvar, ListBase *ch
}
}
+static void expand_idprops(FileData *fd, Main *mainvar, IDProperty *prop)
+{
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_ID:
+ expand_doit(fd, mainvar, IDP_Id(prop));
+ break;
+ case IDP_IDPARRAY:
+ {
+ IDProperty *idp_array = IDP_IDPArray(prop);
+ for (int i = 0; i < prop->len; i++) {
+ expand_idprops(fd, mainvar, &idp_array[i]);
+ }
+ break;
+ }
+ case IDP_GROUP:
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ expand_idprops(fd, mainvar, loop);
+ }
+ break;
+ }
+}
+
static void expand_fmodifiers(FileData *fd, Main *mainvar, ListBase *list)
{
FModifier *fcm;
@@ -8995,6 +9157,7 @@ static void expand_key(FileData *fd, Main *mainvar, Key *key)
static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
{
bNode *node;
+ bNodeSocket *sock;
if (ntree->adt)
expand_animdata(fd, mainvar, ntree->adt);
@@ -9003,10 +9166,22 @@ static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
expand_doit(fd, mainvar, ntree->gpd);
for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id && node->type != CMP_NODE_R_LAYERS)
+ if (node->id && node->type != CMP_NODE_R_LAYERS) {
expand_doit(fd, mainvar, node->id);
+ }
+
+ expand_idprops(fd, mainvar, node->prop);
+
+ for (sock = node->inputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
+ for (sock = node->outputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
}
+ for (sock = ntree->inputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
+ for (sock = ntree->outputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
}
static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
@@ -9224,17 +9399,6 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb)
}
}
-#if 0 /* Disabled as it doesn't actually do anything except recurse... */
-static void expand_bones(FileData *fd, Main *mainvar, Bone *bone)
-{
- Bone *curBone;
-
- for (curBone = bone->childbase.first; curBone; curBone=curBone->next) {
- expand_bones(fd, mainvar, curBone);
- }
-}
-#endif
-
static void expand_pose(FileData *fd, Main *mainvar, bPose *pose)
{
bPoseChannel *chan;
@@ -9244,28 +9408,32 @@ static void expand_pose(FileData *fd, Main *mainvar, bPose *pose)
for (chan = pose->chanbase.first; chan; chan = chan->next) {
expand_constraints(fd, mainvar, &chan->constraints);
+ expand_idprops(fd, mainvar, chan->prop);
expand_doit(fd, mainvar, chan->custom);
}
}
+static void expand_bones(FileData *fd, Main *mainvar, Bone *bone)
+{
+ expand_idprops(fd, mainvar, bone->prop);
+
+ for (Bone *curBone = bone->childbase.first; curBone; curBone = curBone->next) {
+ expand_bones(fd, mainvar, curBone);
+ }
+}
+
static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm)
-{
+{
if (arm->adt)
expand_animdata(fd, mainvar, arm->adt);
-
-#if 0 /* Disabled as this currently only recurses down the chain doing nothing */
- {
- Bone *curBone;
-
- for (curBone = arm->bonebase.first; curBone; curBone=curBone->next) {
- expand_bones(fd, mainvar, curBone);
- }
+
+ for (Bone *curBone = arm->bonebase.first; curBone; curBone = curBone->next) {
+ expand_bones(fd, mainvar, curBone);
}
-#endif
}
static void expand_object_expandModifiers(
- void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
+ void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cb_flag))
{
struct { FileData *fd; Main *mainvar; } *data= userData;
@@ -9489,6 +9657,8 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
SEQ_BEGIN (sce->ed, seq)
{
+ expand_idprops(fd, mainvar, seq->prop);
+
if (seq->scene) expand_doit(fd, mainvar, seq->scene);
if (seq->scene_camera) expand_doit(fd, mainvar, seq->scene_camera);
if (seq->clip) expand_doit(fd, mainvar, seq->clip);
@@ -9646,6 +9816,8 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
id = lbarray[a]->first;
while (id) {
if (id->tag & LIB_TAG_NEED_EXPAND) {
+ expand_idprops(fd, mainvar, id->properties);
+
switch (GS(id->name)) {
case ID_OB:
expand_object(fd, mainvar, (Object *)id);
@@ -9725,6 +9897,8 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_CF:
expand_cachefile(fd, mainvar, (CacheFile *)id);
break;
+ default:
+ break;
}
do_it = true;
@@ -9783,9 +9957,15 @@ static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Libra
if (active_lay) {
ob->lay = active_lay;
}
+ if (flag & FILE_AUTOSELECT) {
+ /* Note that link_object_postprocess() already checks for FILE_AUTOSELECT flag,
+ * but it will miss objects from non-instanciated groups... */
+ ob->flag |= SELECT;
+ /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
+ }
- base->lay = ob->lay;
base->object = ob;
+ base->lay = ob->lay;
base->flag = ob->flag;
CLAMP_MIN(ob->id.us, 0);
@@ -9966,7 +10146,7 @@ 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, const bool use_placeholders, const bool force_indirect)
+ Scene *scene, View3D *v3d, const bool use_placeholders, const bool force_indirect)
{
ID *id = link_named_part(mainl, fd, idcode, name, use_placeholders, force_indirect);
@@ -10105,6 +10285,32 @@ Main *BLO_library_link_begin(Main *mainvar, BlendHandle **bh, const char *filepa
return library_link_begin(mainvar, &fd, filepath);
}
+static void split_main_newid(Main *mainptr, Main *main_newid)
+{
+ /* We only copy the necessary subset of data in this temp main. */
+ main_newid->versionfile = mainptr->versionfile;
+ main_newid->subversionfile = mainptr->subversionfile;
+ BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name));
+ main_newid->curlib = mainptr->curlib;
+
+ ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray_newid[MAX_LIBARRAY];
+ int i = set_listbasepointers(mainptr, lbarray);
+ set_listbasepointers(main_newid, lbarray_newid);
+ while (i--) {
+ BLI_listbase_clear(lbarray_newid[i]);
+
+ for (ID *id = lbarray[i]->first, *idnext; id; id = idnext) {
+ idnext = id->next;
+
+ if (id->tag & LIB_TAG_NEW) {
+ BLI_remlink(lbarray[i], id);
+ BLI_addtail(lbarray_newid[i], id);
+ }
+ }
+ }
+}
+
/* scene and v3d may be NULL. */
static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene *scene, View3D *v3d)
{
@@ -10133,10 +10339,28 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene
blo_join_main((*fd)->mainlist);
mainvar = (*fd)->mainlist->first;
- MEM_freeN((*fd)->mainlist);
mainl = NULL; /* blo_join_main free's mainl, cant use anymore */
lib_link_all(*fd, mainvar);
+
+ /* Yep, second splitting... but this is a very cheap operation, so no big deal. */
+ blo_split_main((*fd)->mainlist, mainvar);
+ Main main_newid = {0};
+ for (mainvar = ((Main *)(*fd)->mainlist->first)->next; mainvar; mainvar = mainvar->next) {
+ BLI_assert(mainvar->versionfile != 0);
+ /* We need to split out IDs already existing, or they will go again through do_versions - bad, very bad! */
+ split_main_newid(mainvar, &main_newid);
+
+ do_versions_after_linking(&main_newid);
+
+ add_main_to_main(mainvar, &main_newid);
+ }
+ blo_join_main((*fd)->mainlist);
+ mainvar = (*fd)->mainlist->first;
+ MEM_freeN((*fd)->mainlist);
+
+ BKE_main_id_tag_all(mainvar, LIB_TAG_NEW, false);
+
lib_verify_nodetree(mainvar, false);
fix_relpaths_library(G.main->name, mainvar); /* make all relative paths, relative to the open blend file */
@@ -10307,6 +10531,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
else {
mainptr->curlib->filedata = NULL;
mainptr->curlib->id.tag |= LIB_TAG_MISSING;
+ /* Set lib version to current main one... Makes assert later happy. */
+ mainptr->versionfile = mainptr->curlib->versionfile = mainl->versionfile;
+ mainptr->subversionfile = mainptr->curlib->subversionfile = mainl->subversionfile;
}
if (fd == NULL) {
@@ -10376,14 +10603,19 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
}
/* do versions, link, and free */
+ Main main_newid = {0};
for (mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
- /* some mains still have to be read, then
- * versionfile is still zero! */
+ /* some mains still have to be read, then versionfile is still zero! */
if (mainptr->versionfile) {
+ /* We need to split out IDs already existing, or they will go again through do_versions - bad, very bad! */
+ split_main_newid(mainptr, &main_newid);
+
if (mainptr->curlib->filedata) // can be zero... with shift+f1 append
- do_versions(mainptr->curlib->filedata, mainptr->curlib, mainptr);
+ do_versions(mainptr->curlib->filedata, mainptr->curlib, &main_newid);
else
- do_versions(basefd, NULL, mainptr);
+ do_versions(basefd, NULL, &main_newid);
+
+ add_main_to_main(mainptr, &main_newid);
}
if (mainptr->curlib->filedata)
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 7719aaa2b0d..62ce15a640e 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -81,6 +81,8 @@ typedef struct FileData {
int id_name_offs; /* used to retrieve ID names from (bhead+1) */
int globalf, fileflags; /* for do_versions patching */
+ eBLOReadSkip skip_flags; /* skip some data-blocks */
+
struct OldNewMap *datamap;
struct OldNewMap *globmap;
struct OldNewMap *libmap;
@@ -170,5 +172,7 @@ void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *
void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *main);
void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *main);
+void do_versions_after_linking_270(struct Main *main);
+
#endif
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 907baab0aee..77542d8deb9 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -56,6 +56,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -999,7 +1000,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
{
/* convert extended ascii to utf-8 for text editor */
Text *text;
- for (text = main->text.first; text; text = text->id.next)
+ for (text = main->text.first; text; text = text->id.next) {
if (!(text->flags & TXT_ISEXT)) {
TextLine *tl;
@@ -1012,6 +1013,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
text->curc = 0;
}
}
+ }
}
{
/* set new dynamic paint values */
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 25d78b73d59..095f21a5b06 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -34,6 +34,7 @@
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
@@ -46,6 +47,7 @@
#include "DNA_screen_types.h"
#include "DNA_object_force.h"
#include "DNA_object_types.h"
+#include "DNA_mask_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_particle_types.h"
@@ -57,9 +59,12 @@
#include "DNA_genfile.h"
+#include "BKE_animsys.h"
+#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_mask.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_scene.h"
@@ -74,6 +79,10 @@
#include "BLO_readfile.h"
+#include "NOD_common.h"
+#include "NOD_socket.h"
+#include "NOD_composite.h"
+
#include "readfile.h"
#include "MEM_guardedalloc.h"
@@ -193,6 +202,89 @@ static void do_version_bones_super_bbone(ListBase *lb)
}
}
+/* TODO(sergey): Consider making it somewhat more generic function in BLI_anim.h. */
+static void anim_change_prop_name(FCurve *fcu,
+ const char *prefix,
+ const char *old_prop_name,
+ const char *new_prop_name)
+{
+ const char *old_path = BLI_sprintfN("%s.%s", prefix, old_prop_name);
+ if (STREQ(fcu->rna_path, old_path)) {
+ MEM_freeN(fcu->rna_path);
+ fcu->rna_path = BLI_sprintfN("%s.%s", prefix, new_prop_name);
+ }
+ MEM_freeN((char *)old_path);
+}
+
+static void do_version_hue_sat_node(bNodeTree *ntree, bNode *node)
+{
+ if (node->storage == NULL) {
+ return;
+ }
+
+ /* Make sure new sockets are properly created. */
+ node_verify_socket_templates(ntree, node);
+ /* Convert value from old storage to new sockets. */
+ NodeHueSat *nhs = node->storage;
+ bNodeSocket *hue = nodeFindSocket(node, SOCK_IN, "Hue"),
+ *saturation = nodeFindSocket(node, SOCK_IN, "Saturation"),
+ *value = nodeFindSocket(node, SOCK_IN, "Value");
+ ((bNodeSocketValueFloat *)hue->default_value)->value = nhs->hue;
+ ((bNodeSocketValueFloat *)saturation->default_value)->value = nhs->sat;
+ ((bNodeSocketValueFloat *)value->default_value)->value = nhs->val;
+ /* Take care of possible animation. */
+ AnimData *adt = BKE_animdata_from_id(&ntree->id);
+ if (adt != NULL && adt->action != NULL) {
+ const char *prefix = BLI_sprintfN("nodes[\"%s\"]", node->name);
+ for (FCurve *fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ if (STRPREFIX(fcu->rna_path, prefix)) {
+ anim_change_prop_name(fcu, prefix, "color_hue", "inputs[1].default_value");
+ anim_change_prop_name(fcu, prefix, "color_saturation", "inputs[2].default_value");
+ anim_change_prop_name(fcu, prefix, "color_value", "inputs[3].default_value");
+ }
+ }
+ MEM_freeN((char *)prefix);
+ }
+ /* Free storage, it is no longer used. */
+ MEM_freeN(node->storage);
+ node->storage = NULL;
+}
+
+static void do_versions_compositor_render_passes_storage(bNode *node)
+{
+ int pass_index = 0;
+ const char *sockname;
+ for (bNodeSocket *sock = node->outputs.first; sock && pass_index < 31; sock = sock->next, pass_index++) {
+ if (sock->storage == NULL) {
+ NodeImageLayer *sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
+ sock->storage = sockdata;
+ BLI_strncpy(sockdata->pass_name, node_cmp_rlayers_sock_to_pass(pass_index), sizeof(sockdata->pass_name));
+
+ if (pass_index == 0) sockname = "Image";
+ else if (pass_index == 1) sockname = "Alpha";
+ else sockname = node_cmp_rlayers_sock_to_pass(pass_index);
+ BLI_strncpy(sock->name, sockname, sizeof(sock->name));
+ }
+ }
+}
+
+static void do_versions_compositor_render_passes(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_R_LAYERS) {
+ /* First we make sure existing sockets have proper names.
+ * This is important because otherwise verification will
+ * drop links from sockets which were renamed.
+ */
+ do_versions_compositor_render_passes_storage(node);
+ /* Make sure new sockets are properly created. */
+ node_verify_socket_templates(ntree, node);
+ /* Make sure all possibly created sockets have proper storage. */
+ do_versions_compositor_render_passes_storage(node);
+ }
+ }
+}
+
void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
if (!MAIN_VERSION_ATLEAST(main, 270, 0)) {
@@ -1145,12 +1237,19 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
SEQ_BEGIN (scene->ed, seq)
{
- if (seq->type == SEQ_TYPE_TEXT) {
- TextVars *data = seq->effectdata;
- if (data->color[3] == 0.0f) {
- copy_v4_fl(data->color, 1.0f);
- data->shadow_color[3] = 1.0f;
- }
+ if (seq->type != SEQ_TYPE_TEXT) {
+ continue;
+ }
+
+ if (seq->effectdata == NULL) {
+ struct SeqEffectHandle effect_handle = BKE_sequence_get_effect(seq);
+ effect_handle.init(seq);
+ }
+
+ TextVars *data = seq->effectdata;
+ if (data->color[3] == 0.0f) {
+ copy_v4_fl(data->color, 1.0f);
+ data->shadow_color[3] = 1.0f;
}
}
SEQ_END
@@ -1204,7 +1303,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)
+ camera->stereo.pole_merge_angle_to == 0.0f)
{
camera->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
camera->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
@@ -1472,5 +1571,154 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
for (Brush *br = main->brush.first; br; br = br->id.next) {
br->fill_threshold /= sqrt_3;
}
+
+ /* Custom motion paths */
+ if (!DNA_struct_elem_find(fd->filesdna, "bMotionPath", "int", "line_thickness")) {
+ Object *ob;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ bMotionPath *mpath;
+ bPoseChannel *pchan;
+ mpath = ob->mpath;
+ if (mpath) {
+ mpath->color[0] = 1.0f;
+ mpath->color[1] = 0.0f;
+ mpath->color[2] = 0.0f;
+ mpath->line_thickness = 1;
+ mpath->flag |= MOTIONPATH_FLAG_LINES;
+ }
+ /* bones motion path */
+ if (ob->pose) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ mpath = pchan->mpath;
+ if (mpath) {
+ mpath->color[0] = 1.0f;
+ mpath->color[1] = 0.0f;
+ mpath->color[2] = 0.0f;
+ mpath->line_thickness = 1;
+ mpath->flag |= MOTIONPATH_FLAG_LINES;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 278, 5)) {
+ /* Mask primitive adding code was not initializing correctly id_type of its points' parent. */
+ for (Mask *mask = main->mask.first; mask; mask = mask->id.next) {
+ for (MaskLayer *mlayer = mask->masklayers.first; mlayer; mlayer = mlayer->next) {
+ for (MaskSpline *mspline = mlayer->splines.first; mspline; mspline = mspline->next) {
+ int i = 0;
+ for (MaskSplinePoint *mspoint = mspline->points; i < mspline->tot_point; mspoint++, i++) {
+ if (mspoint->parent.id_type == 0) {
+ BKE_mask_parent_init(&mspoint->parent);
+ }
+ }
+ }
+ }
+ }
+
+ /* Fix for T50736, Glare comp node using same var for two different things. */
+ if (!DNA_struct_elem_find(fd->filesdna, "NodeGlare", "char", "star_45")) {
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ ntreeSetTypes(NULL, ntree);
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_GLARE) {
+ NodeGlare *ndg = node->storage;
+ switch (ndg->type) {
+ case 2: /* Grrrr! magic numbers :( */
+ ndg->streaks = ndg->angle;
+ break;
+ case 0:
+ ndg->star_45 = ndg->angle != 0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SurfaceDeformModifierData", "float", "mat[4][4]")) {
+ for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_SurfaceDeform) {
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ unit_m4(smd->mat);
+ }
+ }
+ }
+ }
+
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ do_versions_compositor_render_passes(ntree);
+ }
+ } FOREACH_NODETREE_END
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 279, 0)) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ if (scene->r.im_format.exr_codec == R_IMF_EXR_CODEC_DWAB) {
+ scene->r.im_format.exr_codec = R_IMF_EXR_CODEC_DWAA;
+ }
+ }
+
+ /* Fix related to VGroup modifiers creating named defgroup CD layers! See T51520. */
+ for (Mesh *me = main->mesh.first; me; me = me->id.next) {
+ CustomData_set_layer_name(&me->vdata, CD_MDEFORMVERT, 0, "");
+ }
+ }
+
+ {
+ /* Fix for invalid state of screen due to bug in older versions. */
+ for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) {
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ if (sa->full && sc->state == SCREENNORMAL) {
+ sa->full = NULL;
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "falloff_angle")) {
+ for (Brush *br = main->brush.first; br; br = br->id.next) {
+ br->falloff_angle = DEG2RADF(80);
+ br->flag &= ~(
+ BRUSH_FLAG_DEPRECATED_1 | BRUSH_FLAG_DEPRECATED_2 |
+ BRUSH_FLAG_DEPRECATED_3 | BRUSH_FLAG_DEPRECATED_4 |
+ BRUSH_FRONTFACE_FALLOFF);
+ }
+
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+ for (int i = 0; i < 2; i++) {
+ VPaint *vp = i ? ts->vpaint : ts->wpaint;
+ if (vp != NULL) {
+ /* remove all other flags */
+ vp->flag &= (VP_FLAG_VGROUP_RESTRICT);
+ }
+ }
+ }
+ }
+ }
+}
+
+void do_versions_after_linking_270(Main *main)
+{
+ /* To be added to next subversion bump! */
+ if (!MAIN_VERSION_ATLEAST(main, 279, 0)) {
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ ntreeSetTypes(NULL, ntree);
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_HUE_SAT) {
+ do_version_hue_sat_node(ntree, node);
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 99d9e140481..3d3e73eb470 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -58,6 +58,9 @@ void BLO_update_defaults_userpref_blend(void)
U.uiflag |= USER_QUIT_PROMPT;
U.uiflag |= USER_CONTINUOUS_MOUSE;
+ /* See T45301 */
+ U.uiflag |= USER_LOCK_CURSOR_ADJUST;
+
U.versions = 1;
U.savetime = 2;
@@ -68,6 +71,18 @@ void BLO_update_defaults_userpref_blend(void)
* but take care since some hardware has driver bugs here (T46962).
* Further hardware workarounds should be made in gpu_extensions.c */
U.glalphaclip = (1.0f / 255);
+
+ /* default so DPI is detected automatically */
+ U.dpi = 0;
+ U.ui_scale = 1.0f;
+
+#ifdef WITH_PYTHON_SECURITY
+ /* use alternative setting for security nuts
+ * otherwise we'd need to patch the binary blob - startup.blend.c */
+ U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
+#else
+ U.flag &= ~USER_SCRIPT_AUTOEXEC_DISABLE;
+#endif
}
/**
@@ -94,6 +109,16 @@ void BLO_update_defaults_startup_blend(Main *bmain)
sculpt->detail_size = 12;
}
+ if (ts->vpaint) {
+ VPaint *vp = ts->vpaint;
+ vp->radial_symm[0] = vp->radial_symm[1] = vp->radial_symm[2] = 1;
+ }
+
+ if (ts->wpaint) {
+ VPaint *wp = ts->wpaint;
+ wp->radial_symm[0] = wp->radial_symm[1] = wp->radial_symm[2] = 1;
+ }
+
if (ts->gp_sculpt.brush[0].size == 0) {
GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
GP_EditBrush_Data *brush;
@@ -221,6 +246,20 @@ void BLO_update_defaults_startup_blend(Main *bmain)
br->ob_mode = OB_MODE_TEXTURE_PAINT;
}
+ /* Vertex/Weight Paint */
+ br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Average");
+ if (!br) {
+ br = BKE_brush_add(bmain, "Average", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT);
+ br->vertexpaint_tool = PAINT_BLEND_AVERAGE;
+ br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT;
+ }
+ br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Smear");
+ if (!br) {
+ br = BKE_brush_add(bmain, "Smear", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT);
+ br->vertexpaint_tool = PAINT_BLEND_SMEAR;
+ br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT;
+ }
+
br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Mask");
if (br) {
br->imagepaint_tool = PAINT_TOOL_MASK;
@@ -230,13 +269,13 @@ void BLO_update_defaults_startup_blend(Main *bmain)
/* remove polish brush (flatten/contrast does the same) */
br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Polish");
if (br) {
- BKE_libblock_free(bmain, br);
+ BKE_libblock_delete(bmain, br);
}
/* remove brush brush (huh?) from some modes (draw brushes do the same) */
br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Brush");
if (br) {
- BKE_libblock_free(bmain, br);
+ BKE_libblock_delete(bmain, br);
}
/* remove draw brush from texpaint (draw brushes do the same) */
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index f2d42849bcc..ad37679800b 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -2296,11 +2296,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
/* during 2.41 images with this name were used for viewer node output, lets fix that */
if (main->versionfile == 241) {
Image *ima;
- for (ima = main->image.first; ima; ima = ima->id.next)
+ for (ima = main->image.first; ima; ima = ima->id.next) {
if (STREQ(ima->name, "Compositor")) {
strcpy(ima->id.name + 2, "Viewer Node");
strcpy(ima->name, "Viewer Node");
}
+ }
}
}
@@ -2910,12 +2911,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
Scene *sce;
for (sce = main->scene.first; sce; sce = sce->id.next) {
if (sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[1] ||
- sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[2] ||
- sce->toolsettings->skgen_subdivisions[1] == sce->toolsettings->skgen_subdivisions[2])
+ sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[2] ||
+ sce->toolsettings->skgen_subdivisions[1] == sce->toolsettings->skgen_subdivisions[2])
{
- sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
- sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
- sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
+ sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
+ sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
+ sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
}
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index ad1999c0bc7..2648ebdc395 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -78,7 +78,7 @@
* - 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``.
+ * - write #USER (#UserDef struct) if filename is ``~/.config/blender/X.XX/config/startup.blend``.
*/
@@ -797,30 +797,22 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves)
}
}
-static void write_actions(WriteData *wd, ListBase *idbase)
+static void write_action(WriteData *wd, 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);
- write_iddata(wd, &act->id);
+ if (act->id.us > 0 || wd->current) {
+ writestruct(wd, ID_AC, bAction, 1, act);
+ write_iddata(wd, &act->id);
- write_fcurves(wd, &act->curves);
+ write_fcurves(wd, &act->curves);
- for (grp = act->groups.first; grp; grp = grp->next) {
- writestruct(wd, DATA, bActionGroup, 1, grp);
- }
+ for (bActionGroup *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 (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ writestruct(wd, DATA, TimeMarker, 1, marker);
}
}
-
- mywrite_flush(wd);
}
static void write_keyingsets(WriteData *wd, ListBase *list)
@@ -969,7 +961,7 @@ static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree),
}
}
/* this is only direct data, tree itself should have been written */
-static void write_nodetree(WriteData *wd, bNodeTree *ntree)
+static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree)
{
bNode *node;
bNodeSocket *sock;
@@ -1030,6 +1022,25 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
{
/* pass */
}
+ else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_GLARE)) {
+ /* Simple forward compat for fix for T50736.
+ * Not ideal (there is no ideal solution here), but should do for now. */
+ NodeGlare *ndg = node->storage;
+ /* Not in undo case. */
+ if (!wd->current) {
+ switch (ndg->type) {
+ case 2: /* Grrrr! magic numbers :( */
+ ndg->angle = ndg->streaks;
+ break;
+ case 0:
+ ndg->angle = ndg->star_45;
+ break;
+ default:
+ break;
+ }
+ }
+ writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ }
else {
writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
@@ -1041,7 +1052,7 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
writestruct(wd, DATA, NodeImageMultiFileSocket, 1, sock->storage);
}
}
- if (node->type == CMP_NODE_IMAGE) {
+ if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) {
/* write extra socket info */
for (sock = node->outputs.first; sock; sock = sock->next) {
writestruct(wd, DATA, NodeImageLayer, 1, sock->storage);
@@ -1278,68 +1289,60 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches)
}
}
}
-static void write_particlesettings(WriteData *wd, ListBase *idbase)
-{
- ParticleSettings *part;
- ParticleDupliWeight *dw;
- GroupObject *go;
- int a;
- part = idbase->first;
- while (part) {
- if (part->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_PA, ParticleSettings, 1, part);
- write_iddata(wd, &part->id);
+static void write_particlesettings(WriteData *wd, ParticleSettings *part)
+{
+ if (part->id.us > 0 || wd->current) {
+ /* write LibData */
+ 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->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) {
- write_curvemapping(wd, part->roughcurve);
- }
+ if (part->clumpcurve) {
+ write_curvemapping(wd, part->clumpcurve);
+ }
+ if (part->roughcurve) {
+ write_curvemapping(wd, part->roughcurve);
+ }
- dw = part->dupliweights.first;
- for (; dw; dw = dw->next) {
- /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */
- if (dw->ob != NULL) {
- dw->index = 0;
- if (part->dup_group) { /* can be NULL if lining fails or set to None */
- for (go = part->dup_group->gobject.first; go && go->ob != dw->ob; go = go->next, dw->index++);
- }
+ for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) {
+ /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */
+ if (dw->ob != NULL) {
+ dw->index = 0;
+ if (part->dup_group) { /* can be NULL if lining fails or set to None */
+ for (GroupObject *go = part->dup_group->gobject.first;
+ go && go->ob != dw->ob;
+ 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);
+ if (part->boids && part->phystype == PART_PHYS_BOIDS) {
+ writestruct(wd, DATA, BoidSettings, 1, part->boids);
- 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);
+ for (BoidState *state = part->boids->states.first; state; state = state->next) {
+ write_boid_state(wd, state);
}
+ }
+ if (part->fluid && part->phystype == PART_PHYS_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 (int a = 0; a < MAX_MTEX; a++) {
+ if (part->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, part->mtex[a]);
}
}
- part = part->id.next;
}
}
+
static void write_particlesystems(WriteData *wd, ListBase *particles)
{
ParticleSystem *psys = particles->first;
@@ -1830,242 +1833,207 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
writedata(wd, DATA, sizeof(float[3]) * csmd->bind_coords_num, csmd->bind_coords);
}
}
- }
-}
+ else if (md->type == eModifierType_SurfaceDeform) {
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
-static void write_objects(WriteData *wd, ListBase *idbase)
-{
- Object *ob;
+ writestruct(wd, DATA, SDefVert, smd->numverts, smd->verts);
- ob = idbase->first;
- while (ob) {
- if (ob->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_OB, Object, 1, ob);
- write_iddata(wd, &ob->id);
+ if (smd->verts) {
+ for (int i = 0; i < smd->numverts; i++) {
+ writestruct(wd, DATA, SDefBind, smd->verts[i].numbinds, smd->verts[i].binds);
- if (ob->adt) {
- write_animdata(wd, ob->adt);
- }
+ if (smd->verts[i].binds) {
+ for (int j = 0; j < smd->verts[i].numbinds; j++) {
+ writedata(wd, DATA, sizeof(int) * smd->verts[i].binds[j].numverts, smd->verts[i].binds[j].vert_inds);
- /* direct data */
- 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);
- write_controllers(wd, &ob->controllers);
- write_actuators(wd, &ob->actuators);
-
- if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
- if (arm && ob->pose && arm->act_bone) {
- BLI_strncpy(ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone));
+ if (smd->verts[i].binds[j].mode == MOD_SDEF_MODE_CENTROID ||
+ smd->verts[i].binds[j].mode == MOD_SDEF_MODE_LOOPTRI)
+ {
+ writedata(wd, DATA, sizeof(float) * 3, smd->verts[i].binds[j].vert_weights);
+ }
+ else {
+ writedata(wd, DATA, sizeof(float) * smd->verts[i].binds[j].numverts, smd->verts[i].binds[j].vert_weights);
+ }
+ }
+ }
}
}
+ }
+ }
+}
- write_pose(wd, ob->pose);
- write_defgroups(wd, &ob->defbase);
- write_constraints(wd, &ob->constraints);
- write_motionpath(wd, ob->mpath);
+static void write_object(WriteData *wd, Object *ob)
+{
+ if (ob->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_OB, Object, 1, ob);
+ write_iddata(wd, &ob->id);
- 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, BulletSoftBody, 1, ob->bsoft);
+ if (ob->adt) {
+ write_animdata(wd, ob->adt);
+ }
- 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);
- }
- if (ob->rigidbody_constraint) {
- writestruct(wd, DATA, RigidBodyCon, 1, ob->rigidbody_constraint);
- }
+ /* direct data */
+ 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);
+ write_controllers(wd, &ob->controllers);
+ write_actuators(wd, &ob->actuators);
- if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
- writestruct(wd, DATA, ImageUser, 1, ob->iuser);
+ if (ob->type == OB_ARMATURE) {
+ bArmature *arm = ob->data;
+ if (arm && ob->pose && arm->act_bone) {
+ BLI_strncpy(ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone));
}
+ }
- write_particlesystems(wd, &ob->particlesystem);
- write_modifiers(wd, &ob->modifiers);
+ write_pose(wd, ob->pose);
+ write_defgroups(wd, &ob->defbase);
+ write_constraints(wd, &ob->constraints);
+ write_motionpath(wd, ob->mpath);
- writelist(wd, DATA, LinkData, &ob->pc_ids);
- writelist(wd, DATA, LodLevel, &ob->lodlevels);
+ 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, BulletSoftBody, 1, ob->bsoft);
- write_previews(wd, ob->preview);
+ 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);
+ }
+ if (ob->rigidbody_constraint) {
+ writestruct(wd, DATA, RigidBodyCon, 1, ob->rigidbody_constraint);
+ }
- ob = ob->id.next;
- }
+ if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
+ writestruct(wd, DATA, ImageUser, 1, ob->iuser);
+ }
- mywrite_flush(wd);
-}
+ write_particlesystems(wd, &ob->particlesystem);
+ write_modifiers(wd, &ob->modifiers);
+ writelist(wd, DATA, LinkData, &ob->pc_ids);
+ writelist(wd, DATA, LodLevel, &ob->lodlevels);
-static void write_vfonts(WriteData *wd, ListBase *idbase)
-{
- VFont *vf;
- PackedFile *pf;
+ write_previews(wd, ob->preview);
+ }
+}
- vf = idbase->first;
- while (vf) {
- if (vf->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_VF, VFont, 1, vf);
- write_iddata(wd, &vf->id);
- /* direct data */
+static void write_vfont(WriteData *wd, VFont *vf)
+{
+ if (vf->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_VF, VFont, 1, vf);
+ write_iddata(wd, &vf->id);
- if (vf->packedfile) {
- pf = vf->packedfile;
- writestruct(wd, DATA, PackedFile, 1, pf);
- writedata(wd, DATA, pf->size, pf->data);
- }
+ /* direct data */
+ if (vf->packedfile) {
+ PackedFile *pf = vf->packedfile;
+ writestruct(wd, DATA, PackedFile, 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
}
-
- vf = vf->id.next;
}
-
- mywrite_flush(wd);
}
-static void write_keys(WriteData *wd, ListBase *idbase)
+static void write_key(WriteData *wd, Key *key)
{
- Key *key;
- KeyBlock *kb;
-
- key = idbase->first;
- while (key) {
- if (key->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_KE, Key, 1, key);
- write_iddata(wd, &key->id);
-
- if (key->adt) {
- write_animdata(wd, key->adt);
- }
+ if (key->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_KE, Key, 1, key);
+ write_iddata(wd, &key->id);
- /* direct data */
- 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;
- }
+ if (key->adt) {
+ write_animdata(wd, key->adt);
}
- key = key->id.next;
+ /* direct data */
+ for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ writestruct(wd, DATA, KeyBlock, 1, kb);
+ if (kb->data) {
+ writedata(wd, DATA, kb->totelem * key->elemsize, kb->data);
+ }
+ }
}
-
- mywrite_flush(wd);
}
-static void write_cameras(WriteData *wd, ListBase *idbase)
+static void write_camera(WriteData *wd, Camera *cam)
{
- Camera *cam;
-
- cam = idbase->first;
- while (cam) {
- if (cam->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_CA, Camera, 1, cam);
- write_iddata(wd, &cam->id);
+ if (cam->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_CA, Camera, 1, cam);
+ write_iddata(wd, &cam->id);
- if (cam->adt) {
- write_animdata(wd, cam->adt);
- }
+ if (cam->adt) {
+ write_animdata(wd, cam->adt);
}
-
- cam = cam->id.next;
}
}
-static void write_mballs(WriteData *wd, ListBase *idbase)
+static void write_mball(WriteData *wd, MetaBall *mb)
{
- MetaBall *mb;
- MetaElem *ml;
-
- mb = idbase->first;
- while (mb) {
- if (mb->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_MB, MetaBall, 1, mb);
- write_iddata(wd, &mb->id);
+ if (mb->id.us > 0 || wd->current) {
+ /* write LibData */
+ 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);
- }
+ /* direct data */
+ writedata(wd, DATA, sizeof(void *) * mb->totcol, mb->mat);
+ if (mb->adt) {
+ write_animdata(wd, mb->adt);
+ }
- ml = mb->elems.first;
- while (ml) {
- writestruct(wd, DATA, MetaElem, 1, ml);
- ml = ml->next;
- }
+ for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ writestruct(wd, DATA, MetaElem, 1, ml);
}
- mb = mb->id.next;
}
}
-static void write_curves(WriteData *wd, ListBase *idbase)
+static void write_curve(WriteData *wd, Curve *cu)
{
- Curve *cu;
- Nurb *nu;
-
- cu = idbase->first;
- while (cu) {
- if (cu->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_CU, Curve, 1, cu);
- write_iddata(wd, &cu->id);
+ if (cu->id.us > 0 || wd->current) {
+ /* write LibData */
+ 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->adt) {
- write_animdata(wd, cu->adt);
- }
+ /* direct data */
+ 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);
+ 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);
+ }
+ else {
+ /* is also the order of reading */
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ writestruct(wd, DATA, Nurb, 1, nu);
}
- else {
- /* is also the order of reading */
- nu = cu->nurb.first;
- while (nu) {
- writestruct(wd, DATA, Nurb, 1, nu);
- nu = nu->next;
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ writestruct(wd, DATA, BezTriple, nu->pntsu, nu->bezt);
}
- nu = cu->nurb.first;
- while (nu) {
- 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);
}
- 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);
- }
+ if (nu->knotsv) {
+ writedata(wd, DATA, KNOTSV(nu) * sizeof(float), nu->knotsv);
}
- nu = nu->next;
}
}
}
- cu = cu->id.next;
}
-
- mywrite_flush(wd);
}
static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist)
@@ -2182,407 +2150,350 @@ static void write_customdata(
}
}
-static void write_meshes(WriteData *wd, ListBase *idbase)
+static void write_mesh(WriteData *wd, Mesh *mesh)
{
- Mesh *mesh;
- 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 */
+ const bool save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */
+#else
+ const bool save_for_old_blender = false;
#endif
- mesh = idbase->first;
- while (mesh) {
- CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE];
- 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) {
- /* write LibData */
- if (!save_for_old_blender) {
- /* write a copy of the mesh, don't modify in place because it is
- * not thread safe for threaded renders that are reading this */
- Mesh *old_mesh = mesh;
- Mesh copy_mesh = *mesh;
- mesh = &copy_mesh;
+ CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE];
+ 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) {
+ /* write LibData */
+ if (!save_for_old_blender) {
+ /* write a copy of the mesh, don't modify in place because it is
+ * not thread safe for threaded renders that are reading this */
+ Mesh *old_mesh = mesh;
+ Mesh copy_mesh = *mesh;
+ mesh = &copy_mesh;
#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
- /* cache only - don't write */
- mesh->mface = NULL;
- mesh->totface = 0;
- memset(&mesh->fdata, 0, sizeof(mesh->fdata));
+ /* cache only - don't write */
+ mesh->mface = NULL;
+ mesh->totface = 0;
+ memset(&mesh->fdata, 0, sizeof(mesh->fdata));
#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
- /**
- * Those calls:
- * - Reduce mesh->xdata.totlayer to number of layers to write.
- * - Fill xlayers with those layers to be written.
- * Note that mesh->xdata is from now on invalid for Blender, but this is why the whole mesh is
- * a temp local copy!
- */
- CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
- CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
+ /**
+ * Those calls:
+ * - Reduce mesh->xdata.totlayer to number of layers to write.
+ * - Fill xlayers with those layers to be written.
+ * Note that mesh->xdata is from now on invalid for Blender, but this is why the whole mesh is
+ * a temp local copy!
+ */
+ CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
+ CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
#ifndef USE_BMESH_SAVE_WITHOUT_MFACE /* Do not copy org fdata in this case!!! */
- CustomData_file_write_prepare(&mesh->fdata, &flayers, flayers_buff, ARRAY_SIZE(flayers_buff));
+ CustomData_file_write_prepare(&mesh->fdata, &flayers, flayers_buff, ARRAY_SIZE(flayers_buff));
#else
- flayers = flayers_buff;
+ flayers = flayers_buff;
#endif
- 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));
+ 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);
- write_iddata(wd, &mesh->id);
+ writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
+ write_iddata(wd, &mesh->id);
- /* direct data */
- if (mesh->adt) {
- write_animdata(wd, mesh->adt);
- }
+ /* direct data */
+ if (mesh->adt) {
+ write_animdata(wd, mesh->adt);
+ }
- writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
- writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect);
+ 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);
- write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, -1, 0);
- /* fdata is really a dummy - written so slots align */
- write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, -1, 0);
- write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, -1, 0);
- write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, -1, 0);
+ /* fdata is really a dummy - written so slots align */
+ write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, -1, 0);
- /* restore pointer */
- mesh = old_mesh;
- }
- else {
+ /* restore pointer */
+ mesh = old_mesh;
+ }
+ else {
#ifdef USE_BMESH_SAVE_AS_COMPAT
- /* write a copy of the mesh, don't modify in place because it is
- * not thread safe for threaded renders that are reading this */
- Mesh *old_mesh = mesh;
- Mesh copy_mesh = *mesh;
- mesh = &copy_mesh;
-
- mesh->mpoly = NULL;
- mesh->mface = NULL;
- mesh->totface = 0;
- mesh->totpoly = 0;
- mesh->totloop = 0;
- CustomData_reset(&mesh->fdata);
- CustomData_reset(&mesh->pdata);
- CustomData_reset(&mesh->ldata);
- mesh->edit_btmesh = NULL;
-
- /* now fill in polys to mfaces */
- /* XXX This breaks writing design, by using temp allocated memory, which will likely generate
- * duplicates in stored 'old' addresses.
- * This is very bad, but do not see easy way to avoid this, aside from generating those data
- * outside of save process itself.
- * Maybe we can live with this, though?
- */
- mesh->totface = BKE_mesh_mpoly_to_mface(&mesh->fdata, &old_mesh->ldata, &old_mesh->pdata,
- mesh->totface, old_mesh->totloop, old_mesh->totpoly);
+ /* write a copy of the mesh, don't modify in place because it is
+ * not thread safe for threaded renders that are reading this */
+ Mesh *old_mesh = mesh;
+ Mesh copy_mesh = *mesh;
+ mesh = &copy_mesh;
+
+ mesh->mpoly = NULL;
+ mesh->mface = NULL;
+ mesh->totface = 0;
+ mesh->totpoly = 0;
+ mesh->totloop = 0;
+ CustomData_reset(&mesh->fdata);
+ CustomData_reset(&mesh->pdata);
+ CustomData_reset(&mesh->ldata);
+ mesh->edit_btmesh = NULL;
+
+ /* now fill in polys to mfaces */
+ /* XXX This breaks writing design, by using temp allocated memory, which will likely generate
+ * duplicates in stored 'old' addresses.
+ * This is very bad, but do not see easy way to avoid this, aside from generating those data
+ * outside of save process itself.
+ * Maybe we can live with this, though?
+ */
+ mesh->totface = BKE_mesh_mpoly_to_mface(
+ &mesh->fdata, &old_mesh->ldata, &old_mesh->pdata,
+ mesh->totface, old_mesh->totloop, old_mesh->totpoly);
- BKE_mesh_update_customdata_pointers(mesh, false);
+ BKE_mesh_update_customdata_pointers(mesh, false);
- CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
- CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
- CustomData_file_write_prepare(&mesh->fdata, &flayers, flayers_buff, ARRAY_SIZE(flayers_buff));
+ CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
+ CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
+ CustomData_file_write_prepare(&mesh->fdata, &flayers, flayers_buff, ARRAY_SIZE(flayers_buff));
#if 0
- 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));
+ 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));
#endif
- writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
- write_iddata(wd, &mesh->id);
+ writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
+ write_iddata(wd, &mesh->id);
- /* direct data */
- if (mesh->adt) {
- write_animdata(wd, mesh->adt);
- }
+ /* direct data */
+ if (mesh->adt) {
+ write_animdata(wd, mesh->adt);
+ }
- writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
- /* writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); */ /* pre-bmesh NULL's */
+ 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);
- write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, -1, 0);
- write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, -1, 0);
- /* harmless for older blender versioins but _not_ writing these keeps file size down */
+ write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, -1, 0);
+ /* harmless for older blender versioins but _not_ writing these keeps file size down */
#if 0
- write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, -1, 0);
- write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, -1, 0);
#endif
- CustomData_free(&mesh->fdata, mesh->totface);
- flayers = NULL;
+ CustomData_free(&mesh->fdata, mesh->totface);
+ flayers = NULL;
- /* restore pointer */
- mesh = old_mesh;
+ /* restore pointer */
+ mesh = old_mesh;
#endif /* USE_BMESH_SAVE_AS_COMPAT */
- }
- }
-
- if (vlayers && vlayers != vlayers_buff) {
- MEM_freeN(vlayers);
}
- if (elayers && elayers != elayers_buff) {
- MEM_freeN(elayers);
- }
- if (flayers && flayers != flayers_buff) {
- MEM_freeN(flayers);
- }
- if (llayers && llayers != llayers_buff) {
- MEM_freeN(llayers);
- }
- if (players && players != players_buff) {
- MEM_freeN(players);
- }
-
- mesh = mesh->id.next;
}
- mywrite_flush(wd);
+ if (vlayers && vlayers != vlayers_buff) {
+ MEM_freeN(vlayers);
+ }
+ if (elayers && elayers != elayers_buff) {
+ MEM_freeN(elayers);
+ }
+ if (flayers && flayers != flayers_buff) {
+ MEM_freeN(flayers);
+ }
+ if (llayers && llayers != llayers_buff) {
+ MEM_freeN(llayers);
+ }
+ if (players && players != players_buff) {
+ MEM_freeN(players);
+ }
}
-static void write_lattices(WriteData *wd, ListBase *idbase)
+static void write_lattice(WriteData *wd, Lattice *lt)
{
- Lattice *lt;
-
- lt = idbase->first;
- while (lt) {
- if (lt->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_LT, Lattice, 1, lt);
- write_iddata(wd, &lt->id);
-
- /* write animdata */
- if (lt->adt) {
- write_animdata(wd, lt->adt);
- }
+ if (lt->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_LT, Lattice, 1, lt);
+ write_iddata(wd, &lt->id);
- /* direct data */
- writestruct(wd, DATA, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def);
+ /* write animdata */
+ if (lt->adt) {
+ write_animdata(wd, lt->adt);
+ }
- write_dverts(wd, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert);
+ /* direct data */
+ writestruct(wd, DATA, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def);
- }
- lt = lt->id.next;
+ write_dverts(wd, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert);
}
-
- mywrite_flush(wd);
}
-static void write_images(WriteData *wd, ListBase *idbase)
+static void write_image(WriteData *wd, Image *ima)
{
- Image *ima;
- PackedFile *pf;
- ImageView *iv;
- ImagePackedFile *imapf;
-
- ima = idbase->first;
- while (ima) {
- 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) {
- imapf = ima->packedfiles.first;
- ima->packedfile = imapf->packedfile;
- }
-
- /* write LibData */
- writestruct(wd, ID_IM, Image, 1, ima);
- write_iddata(wd, &ima->id);
+ if (ima->id.us > 0 || wd->current) {
+ ImagePackedFile *imapf;
- for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
- writestruct(wd, DATA, ImagePackedFile, 1, imapf);
- if (imapf->packedfile) {
- pf = imapf->packedfile;
- writestruct(wd, DATA, PackedFile, 1, pf);
- writedata(wd, DATA, pf->size, pf->data);
- }
- }
+ /* Some trickery to keep forward compatibility of packed images. */
+ BLI_assert(ima->packedfile == NULL);
+ if (ima->packedfiles.first != NULL) {
+ imapf = ima->packedfiles.first;
+ ima->packedfile = imapf->packedfile;
+ }
- write_previews(wd, ima->preview);
+ /* write LibData */
+ writestruct(wd, ID_IM, Image, 1, ima);
+ write_iddata(wd, &ima->id);
- for (iv = ima->views.first; iv; iv = iv->next) {
- writestruct(wd, DATA, ImageView, 1, iv);
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
+ writestruct(wd, DATA, ImagePackedFile, 1, imapf);
+ if (imapf->packedfile) {
+ PackedFile *pf = imapf->packedfile;
+ writestruct(wd, DATA, PackedFile, 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
}
- writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format);
+ }
- ima->packedfile = NULL;
+ write_previews(wd, ima->preview);
+
+ for (ImageView *iv = ima->views.first; iv; iv = iv->next) {
+ writestruct(wd, DATA, ImageView, 1, iv);
}
- ima = ima->id.next;
- }
+ writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format);
- mywrite_flush(wd);
+ ima->packedfile = NULL;
+ }
}
-static void write_textures(WriteData *wd, ListBase *idbase)
+static void write_texture(WriteData *wd, Tex *tex)
{
- Tex *tex;
-
- tex = idbase->first;
- while (tex) {
- if (tex->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_TE, Tex, 1, tex);
- write_iddata(wd, &tex->id);
+ if (tex->id.us > 0 || wd->current) {
+ /* write LibData */
+ 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->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);
- }
- }
- 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);
+ /* 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->type == TEX_POINTDENSITY && tex->pd) {
+ writestruct(wd, DATA, PointDensity, 1, tex->pd);
+ if (tex->pd->coba) {
+ writestruct(wd, DATA, ColorBand, 1, tex->pd->coba);
}
-
- /* nodetree is integral part of texture, no libdata */
- if (tex->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, tex->nodetree);
- write_nodetree(wd, tex->nodetree);
+ 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);
+ }
- write_previews(wd, tex->preview);
+ /* nodetree is integral part of texture, no libdata */
+ if (tex->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, tex->nodetree);
+ write_nodetree_nolib(wd, tex->nodetree);
}
- tex = tex->id.next;
- }
- mywrite_flush(wd);
+ write_previews(wd, tex->preview);
+ }
}
-static void write_materials(WriteData *wd, ListBase *idbase)
+static void write_material(WriteData *wd, Material *ma)
{
- Material *ma;
- int a;
-
- ma = idbase->first;
- while (ma) {
- if (ma->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_MA, Material, 1, ma);
- write_iddata(wd, &ma->id);
-
- if (ma->adt) {
- write_animdata(wd, ma->adt);
- }
+ if (ma->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_MA, Material, 1, ma);
+ write_iddata(wd, &ma->id);
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- writestruct(wd, DATA, MTex, 1, ma->mtex[a]);
- }
- }
+ if (ma->adt) {
+ write_animdata(wd, ma->adt);
+ }
- if (ma->ramp_col) {
- writestruct(wd, DATA, ColorBand, 1, ma->ramp_col);
- }
- if (ma->ramp_spec) {
- writestruct(wd, DATA, ColorBand, 1, ma->ramp_spec);
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (ma->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, ma->mtex[a]);
}
+ }
- /* nodetree is integral part of material, no libdata */
- if (ma->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, ma->nodetree);
- write_nodetree(wd, ma->nodetree);
- }
+ if (ma->ramp_col) {
+ writestruct(wd, DATA, ColorBand, 1, ma->ramp_col);
+ }
+ if (ma->ramp_spec) {
+ writestruct(wd, DATA, ColorBand, 1, ma->ramp_spec);
+ }
- write_previews(wd, ma->preview);
+ /* nodetree is integral part of material, no libdata */
+ if (ma->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, ma->nodetree);
+ write_nodetree_nolib(wd, ma->nodetree);
}
- ma = ma->id.next;
+
+ write_previews(wd, ma->preview);
}
}
-static void write_worlds(WriteData *wd, ListBase *idbase)
+static void write_world(WriteData *wd, World *wrld)
{
- World *wrld;
- int a;
-
- wrld = idbase->first;
- while (wrld) {
- if (wrld->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_WO, World, 1, wrld);
- write_iddata(wd, &wrld->id);
-
- if (wrld->adt) {
- write_animdata(wd, wrld->adt);
- }
+ if (wrld->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_WO, World, 1, wrld);
+ write_iddata(wd, &wrld->id);
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a]) {
- writestruct(wd, DATA, MTex, 1, wrld->mtex[a]);
- }
- }
+ if (wrld->adt) {
+ write_animdata(wd, wrld->adt);
+ }
- /* nodetree is integral part of world, no libdata */
- if (wrld->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, wrld->nodetree);
- write_nodetree(wd, wrld->nodetree);
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (wrld->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, wrld->mtex[a]);
}
+ }
- write_previews(wd, wrld->preview);
+ /* nodetree is integral part of world, no libdata */
+ if (wrld->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, wrld->nodetree);
+ write_nodetree_nolib(wd, wrld->nodetree);
}
- wrld = wrld->id.next;
+
+ write_previews(wd, wrld->preview);
}
}
-static void write_lamps(WriteData *wd, ListBase *idbase)
+static void write_lamp(WriteData *wd, Lamp *la)
{
- Lamp *la;
- int a;
-
- la = idbase->first;
- while (la) {
- if (la->id.us > 0 || wd->current) {
- /* write LibData */
- 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]);
- }
- }
+ if (la->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_LA, Lamp, 1, la);
+ write_iddata(wd, &la->id);
- if (la->curfalloff) {
- write_curvemapping(wd, la->curfalloff);
- }
+ if (la->adt) {
+ write_animdata(wd, la->adt);
+ }
- /* nodetree is integral part of lamps, no libdata */
- if (la->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, la->nodetree);
- write_nodetree(wd, la->nodetree);
+ /* direct data */
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (la->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, la->mtex[a]);
}
+ }
- write_previews(wd, la->preview);
+ 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);
+ write_nodetree_nolib(wd, la->nodetree);
}
- la = la->id.next;
- }
- mywrite_flush(wd);
+ write_previews(wd, la->preview);
+ }
}
static void write_sequence_modifiers(WriteData *wd, ListBase *modbase)
@@ -2626,290 +2537,249 @@ static void write_paint(WriteData *wd, Paint *p)
}
}
-static void write_scenes(WriteData *wd, ListBase *scebase)
+static void write_scene(WriteData *wd, Scene *sce)
{
- Scene *sce;
- Base *base;
- Editing *ed;
- Sequence *seq;
- MetaStack *ms;
- Strip *strip;
- TimeMarker *marker;
- TransformOrientation *ts;
- SceneRenderLayer *srl;
- SceneRenderView *srv;
- ToolSettings *tos;
- FreestyleModuleConfig *fmc;
- FreestyleLineSet *fls;
-
- sce = scebase->first;
- while (sce) {
- /* write LibData */
- writestruct(wd, ID_SCE, Scene, 1, sce);
- write_iddata(wd, &sce->id);
+ /* write LibData */
+ 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);
+ if (sce->adt) {
+ write_animdata(wd, sce->adt);
+ }
+ write_keyingsets(wd, &sce->keyingsets);
- /* direct data */
- base = sce->base.first;
- while (base) {
- writestruct(wd, DATA, Base, 1, base);
- base = base->next;
- }
-
- tos = sce->toolsettings;
- writestruct(wd, DATA, ToolSettings, 1, tos);
- if (tos->vpaint) {
- 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);
- }
- if (tos->sculpt) {
- 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);
- }
- /* write grease-pencil drawing brushes to file */
- writelist(wd, DATA, bGPDbrush, &tos->gp_brushes);
- for (bGPDbrush *brush = tos->gp_brushes.first; brush; brush = brush->next) {
- if (brush->cur_sensitivity) {
- write_curvemapping(wd, brush->cur_sensitivity);
- }
- if (brush->cur_strength) {
- write_curvemapping(wd, brush->cur_strength);
- }
- if (brush->cur_jitter) {
- write_curvemapping(wd, brush->cur_jitter);
- }
+ /* direct data */
+ for (Base *base = sce->base.first; base; base = base->next) {
+ writestruct(wd, DATA, Base, 1, base);
+ }
+
+ ToolSettings *tos = sce->toolsettings;
+ writestruct(wd, DATA, ToolSettings, 1, tos);
+ if (tos->vpaint) {
+ 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);
+ }
+ if (tos->sculpt) {
+ 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);
+ }
+ /* write grease-pencil drawing brushes to file */
+ writelist(wd, DATA, bGPDbrush, &tos->gp_brushes);
+ for (bGPDbrush *brush = tos->gp_brushes.first; brush; brush = brush->next) {
+ if (brush->cur_sensitivity) {
+ write_curvemapping(wd, brush->cur_sensitivity);
+ }
+ if (brush->cur_strength) {
+ write_curvemapping(wd, brush->cur_strength);
}
-
+ if (brush->cur_jitter) {
+ write_curvemapping(wd, brush->cur_jitter);
+ }
+ }
+ /* write grease-pencil custom ipo curve to file */
+ if (tos->gp_interpolate.custom_ipo) {
+ write_curvemapping(wd, tos->gp_interpolate.custom_ipo);
+ }
- write_paint(wd, &tos->imapaint.paint);
- ed = sce->ed;
- if (ed) {
- writestruct(wd, DATA, Editing, 1, ed);
+ write_paint(wd, &tos->imapaint.paint);
- /* reset write flags too */
+ Editing *ed = sce->ed;
+ if (ed) {
+ Sequence *seq;
- SEQ_BEGIN(ed, seq)
- {
- if (seq->strip) {
- seq->strip->done = false;
- }
- writestruct(wd, DATA, Sequence, 1, seq);
- }
- SEQ_END
+ writestruct(wd, DATA, Editing, 1, ed);
- SEQ_BEGIN(ed, seq)
- {
- 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;
- }
- }
+ /* reset write flags too */
- writestruct(wd, DATA, Stereo3dFormat, 1, seq->stereo3d_format);
+ SEQ_BEGIN(ed, seq)
+ {
+ if (seq->strip) {
+ seq->strip->done = false;
+ }
+ writestruct(wd, DATA, Sequence, 1, seq);
+ }
+ SEQ_END
- strip = seq->strip;
- writestruct(wd, DATA, Strip, 1, strip);
- if (seq->flag & SEQ_USE_CROP && strip->crop) {
- writestruct(wd, DATA, StripCrop, 1, strip->crop);
- }
- if (seq->flag & SEQ_USE_TRANSFORM && strip->transform) {
- writestruct(wd, DATA, StripTransform, 1, strip->transform);
- }
- if (seq->flag & SEQ_USE_PROXY && 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 (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
- writestruct(wd, DATA, StripElem, 1, strip->stripdata);
+ SEQ_BEGIN(ed, seq)
+ {
+ 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;
}
-
- strip->done = true;
}
- if (seq->prop) {
- IDP_WriteProperty(seq->prop, wd);
+ writestruct(wd, DATA, Stereo3dFormat, 1, seq->stereo3d_format);
+
+ 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);
+ }
+ if (seq->flag & SEQ_USE_TRANSFORM && strip->transform) {
+ writestruct(wd, DATA, StripTransform, 1, strip->transform);
+ }
+ if (seq->flag & SEQ_USE_PROXY && 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 (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
+ writestruct(wd, DATA, StripElem, 1, strip->stripdata);
}
- write_sequence_modifiers(wd, &seq->modifiers);
+ strip->done = true;
}
- 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);
+ if (seq->prop) {
+ IDP_WriteProperty(seq->prop, wd);
}
+
+ write_sequence_modifiers(wd, &seq->modifiers);
}
+ SEQ_END
- 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);
- }
+ /* new; meta stack too, even when its nasty restore code */
+ for (MetaStack *ms = ed->metastack.first; ms; ms = ms->next) {
+ writestruct(wd, DATA, MetaStack, 1, ms);
}
+ }
- 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);
- }
+ 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.ffcodecdata.properties) {
- IDP_WriteProperty(sce->r.ffcodecdata.properties, wd);
+ if (sce->r.avicodecdata->lpParms) {
+ writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
}
+ }
+ 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);
- }
+ /* writing dynamic list of TimeMarkers to the blend file */
+ for (TimeMarker *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);
- }
+ /* writing dynamic list of TransformOrientations to the blend file */
+ for (TransformOrientation *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);
- for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
- writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc);
- }
- for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
- writestruct(wd, DATA, FreestyleLineSet, 1, fls);
- }
+ for (SceneRenderLayer *srl = sce->r.layers.first; srl; srl = srl->next) {
+ writestruct(wd, DATA, SceneRenderLayer, 1, srl);
+ if (srl->prop) {
+ IDP_WriteProperty(srl->prop, wd);
}
-
- /* writing MultiView to the blend file */
- for (srv = sce->r.views.first; srv; srv = srv->next) {
- writestruct(wd, DATA, SceneRenderView, 1, srv);
+ for (FreestyleModuleConfig *fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
+ writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc);
}
-
- if (sce->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, sce->nodetree);
- write_nodetree(wd, sce->nodetree);
+ for (FreestyleLineSet *fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
+ writestruct(wd, DATA, FreestyleLineSet, 1, fls);
}
+ }
- write_view_settings(wd, &sce->view_settings);
+ /* writing MultiView to the blend file */
+ for (SceneRenderView *srv = sce->r.views.first; srv; srv = srv->next) {
+ writestruct(wd, DATA, SceneRenderView, 1, srv);
+ }
- /* 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);
- write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
- }
+ if (sce->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, sce->nodetree);
+ write_nodetree_nolib(wd, sce->nodetree);
+ }
- write_previews(wd, sce->preview);
- write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve);
+ write_view_settings(wd, &sce->view_settings);
- sce = sce->id.next;
+ /* 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);
+ write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
}
- mywrite_flush(wd);
+ write_previews(wd, sce->preview);
+ write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve);
}
-static void write_gpencils(WriteData *wd, ListBase *lb)
+static void write_gpencil(WriteData *wd, bGPdata *gpd)
{
- bGPdata *gpd;
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps;
- bGPDpalette *palette;
-
- 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);
- 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) {
-
- /* write this layer's frames to file */
- 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);
- }
+ if (gpd->id.us > 0 || wd->current) {
+ /* write gpd data block to file */
+ 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 (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* write this layer's frames to file */
+ writelist(wd, DATA, bGPDframe, &gpl->frames);
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* write strokes */
+ writelist(wd, DATA, bGPDstroke, &gpf->strokes);
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points);
}
}
- /* write grease-pencil palettes */
- writelist(wd, DATA, bGPDpalette, &gpd->palettes);
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- writelist(wd, DATA, bGPDpalettecolor, &palette->colors);
- }
}
- }
- mywrite_flush(wd);
+ /* write grease-pencil palettes */
+ writelist(wd, DATA, bGPDpalette, &gpd->palettes);
+ for (bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
+ writelist(wd, DATA, bGPDpalettecolor, &palette->colors);
+ }
+ }
}
-static void write_windowmanagers(WriteData *wd, ListBase *lb)
+static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
{
- wmWindowManager *wm;
- wmWindow *win;
-
- for (wm = lb->first; wm; wm = wm->id.next) {
- writestruct(wd, ID_WM, wmWindowManager, 1, wm);
- write_iddata(wd, &wm->id);
+ 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);
- }
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ writestruct(wd, DATA, wmWindow, 1, win);
+ writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
}
-
- /* typically flushing wouldn't be needed however this data _always_ changes,
- * so flush here for more efficient undo. */
- mywrite_flush(wd);
}
static void write_region(WriteData *wd, ARegion *ar, int spacetype)
@@ -2992,184 +2862,168 @@ static void write_soops(WriteData *wd, SpaceOops *so)
}
}
-static void write_screens(WriteData *wd, ListBase *scrbase)
+static void write_screen(WriteData *wd, bScreen *sc)
{
- bScreen *sc;
- ScrArea *sa;
- ScrVert *sv;
- ScrEdge *se;
-
- sc = scrbase->first;
- while (sc) {
+ /* write LibData */
+ /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
+ writestruct(wd, ID_SCRN, bScreen, 1, sc);
+ write_iddata(wd, &sc->id);
- /* write LibData */
- /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
- writestruct(wd, ID_SCRN, bScreen, 1, sc);
- write_iddata(wd, &sc->id);
+ /* direct data */
+ for (ScrVert *sv = sc->vertbase.first; sv; sv = sv->next) {
+ writestruct(wd, DATA, ScrVert, 1, sv);
+ }
- /* direct data */
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
- writestruct(wd, DATA, ScrVert, 1, sv);
- }
+ for (ScrEdge *se = sc->edgebase.first; se; se = se->next) {
+ writestruct(wd, DATA, ScrEdge, 1, se);
+ }
- for (se = sc->edgebase.first; se; se = se->next) {
- writestruct(wd, DATA, ScrEdge, 1, se);
- }
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+ Panel *pa;
+ uiList *ui_list;
+ uiPreview *ui_preview;
+ PanelCategoryStack *pc_act;
+ ARegion *ar;
- 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);
- writestruct(wd, DATA, ScrArea, 1, sa);
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ write_region(wd, ar, sa->spacetype);
- 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 (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 (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_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);
- }
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (ar = sl->regionbase.first; ar; ar = ar->next) {
+ write_region(wd, ar, sl->spacetype);
}
- sl = sa->spacedata.first;
- while (sl) {
- for (ar = sl->regionbase.first; ar; ar = ar->next) {
- write_region(wd, ar, sl->spacetype);
+ 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 (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->localvd) {
+ writestruct(wd, DATA, View3D, 1, v3d->localvd);
}
- 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);
- }
-
- /* reenable ghost curves */
- sipo->ghostCurves = tmpGhosts;
+ if (v3d->fx_settings.ssao) {
+ writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->fx_settings.ssao);
}
- else if (sl->spacetype == SPACE_BUTS) {
- writestruct(wd, DATA, SpaceButs, 1, sl);
+ if (v3d->fx_settings.dof) {
+ writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof);
}
- else if (sl->spacetype == SPACE_FILE) {
- SpaceFile *sfile = (SpaceFile *)sl;
+ }
+ else if (sl->spacetype == SPACE_IPO) {
+ SpaceIpo *sipo = (SpaceIpo *)sl;
+ ListBase tmpGhosts = sipo->ghostCurves;
- 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_OUTLINER) {
- SpaceOops *so = (SpaceOops *)sl;
- write_soops(wd, so);
- }
- 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_SCRIPT) {
- SpaceScript *scr = (SpaceScript *)sl;
- scr->but_refs = NULL;
- writestruct(wd, DATA, SpaceScript, 1, sl);
- }
- else if (sl->spacetype == SPACE_ACTION) {
- writestruct(wd, DATA, SpaceAction, 1, sl);
- }
- else if (sl->spacetype == SPACE_NLA) {
- SpaceNla *snla = (SpaceNla *)sl;
+ /* temporarily disable ghost curves when saving */
+ sipo->ghostCurves.first = sipo->ghostCurves.last = NULL;
- 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);
+ writestruct(wd, DATA, SpaceIpo, 1, sl);
+ if (sipo->ads) {
+ writestruct(wd, DATA, bDopeSheet, 1, sipo->ads);
}
- 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);
- }
- }
- else if (sl->spacetype == SPACE_LOGIC) {
- writestruct(wd, DATA, SpaceLogic, 1, sl);
- }
- else if (sl->spacetype == SPACE_CONSOLE) {
- SpaceConsole *con = (SpaceConsole *)sl;
- ConsoleLine *cl;
-
- 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, SpaceConsole, 1, sl);
+ /* reenable ghost curves */
+ sipo->ghostCurves = tmpGhosts;
+ }
+ else if (sl->spacetype == SPACE_BUTS) {
+ writestruct(wd, DATA, SpaceButs, 1, 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);
}
- else if (sl->spacetype == SPACE_USERPREF) {
- writestruct(wd, DATA, SpaceUserPref, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_SEQ) {
+ writestruct(wd, DATA, SpaceSeq, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_OUTLINER) {
+ SpaceOops *so = (SpaceOops *)sl;
+ write_soops(wd, so);
+ }
+ 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_SCRIPT) {
+ SpaceScript *scr = (SpaceScript *)sl;
+ scr->but_refs = NULL;
+ writestruct(wd, DATA, SpaceScript, 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_CLIP) {
- writestruct(wd, DATA, SpaceClip, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_TIME) {
+ writestruct(wd, DATA, SpaceTime, 1, sl);
+ }
+ 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);
}
- else if (sl->spacetype == SPACE_INFO) {
- writestruct(wd, DATA, SpaceInfo, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_LOGIC) {
+ writestruct(wd, DATA, SpaceLogic, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_CONSOLE) {
+ SpaceConsole *con = (SpaceConsole *)sl;
+ ConsoleLine *cl;
+
+ 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, SpaceConsole, 1, sl);
- sl = sl->next;
+ }
+ 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_INFO) {
+ writestruct(wd, DATA, SpaceInfo, 1, sl);
}
}
-
- sc = sc->id.next;
}
-
- mywrite_flush(wd);
}
static void write_bone(WriteData *wd, Bone *bone)
@@ -3192,156 +3046,101 @@ static void write_bone(WriteData *wd, Bone *bone)
}
}
-static void write_armatures(WriteData *wd, ListBase *idbase)
+static void write_armature(WriteData *wd, bArmature *arm)
{
- bArmature *arm;
- Bone *bone;
-
- arm = idbase->first;
- while (arm) {
- if (arm->id.us > 0 || wd->current) {
- writestruct(wd, ID_AR, bArmature, 1, arm);
- write_iddata(wd, &arm->id);
+ 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;
- while (bone) {
- write_bone(wd, bone);
- bone = bone->next;
- }
+ /* Direct data */
+ for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
+ write_bone(wd, bone);
}
- arm = arm->id.next;
}
-
- mywrite_flush(wd);
}
-static void write_texts(WriteData *wd, ListBase *idbase)
+static void write_text(WriteData *wd, Text *text)
{
- Text *text;
- TextLine *tmp;
+ if ((text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) {
+ text->flags &= ~TXT_ISEXT;
+ }
- text = idbase->first;
- while (text) {
- if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) {
- text->flags &= ~TXT_ISEXT;
- }
+ /* write LibData */
+ writestruct(wd, ID_TXT, Text, 1, text);
+ write_iddata(wd, &text->id);
- /* write LibData */
- 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->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 */
+ for (TextLine *tmp = text->lines.first; tmp; tmp = tmp->next) {
+ writestruct(wd, DATA, TextLine, 1, tmp);
}
- if (!(text->flags & TXT_ISEXT)) {
- /* now write the text data, in two steps for optimization in the readfunction */
- tmp = text->lines.first;
- while (tmp) {
- writestruct(wd, DATA, TextLine, 1, tmp);
- tmp = tmp->next;
- }
-
- tmp = text->lines.first;
- while (tmp) {
- writedata(wd, DATA, tmp->len + 1, tmp->line);
- tmp = tmp->next;
- }
+ for (TextLine *tmp = text->lines.first; tmp; tmp = tmp->next) {
+ writedata(wd, DATA, tmp->len + 1, tmp->line);
}
-
-
- text = text->id.next;
}
-
- mywrite_flush(wd);
}
-static void write_speakers(WriteData *wd, ListBase *idbase)
+static void write_speaker(WriteData *wd, Speaker *spk)
{
- Speaker *spk;
-
- spk = idbase->first;
- while (spk) {
- if (spk->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_SPK, Speaker, 1, spk);
- write_iddata(wd, &spk->id);
+ if (spk->id.us > 0 || wd->current) {
+ /* write LibData */
+ 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;
}
}
-static void write_sounds(WriteData *wd, ListBase *idbase)
+static void write_sound(WriteData *wd, bSound *sound)
{
- bSound *sound;
-
- PackedFile *pf;
-
- sound = idbase->first;
- while (sound) {
- if (sound->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_SO, bSound, 1, sound);
- write_iddata(wd, &sound->id);
+ if (sound->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_SO, bSound, 1, sound);
+ write_iddata(wd, &sound->id);
- if (sound->packedfile) {
- pf = sound->packedfile;
- writestruct(wd, DATA, PackedFile, 1, pf);
- writedata(wd, DATA, pf->size, pf->data);
- }
+ if (sound->packedfile) {
+ PackedFile *pf = sound->packedfile;
+ writestruct(wd, DATA, PackedFile, 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
}
- sound = sound->id.next;
}
-
- mywrite_flush(wd);
}
-static void write_groups(WriteData *wd, ListBase *idbase)
+static void write_group(WriteData *wd, Group *group)
{
- Group *group;
- GroupObject *go;
-
- 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);
- write_iddata(wd, &group->id);
+ if (group->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_GR, Group, 1, group);
+ write_iddata(wd, &group->id);
- write_previews(wd, group->preview);
+ write_previews(wd, group->preview);
- go = group->gobject.first;
- while (go) {
- writestruct(wd, DATA, GroupObject, 1, go);
- go = go->next;
- }
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
+ writestruct(wd, DATA, GroupObject, 1, go);
}
}
-
- mywrite_flush(wd);
}
-static void write_nodetrees(WriteData *wd, ListBase *idbase)
+static void write_nodetree(WriteData *wd, bNodeTree *ntree)
{
- 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);
- /* 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);
+ 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);
- }
+ write_nodetree_nolib(wd, ntree);
}
}
@@ -3415,53 +3214,41 @@ static void customnodes_free_deprecated_data(Main *mainvar)
}
#endif
-static void write_brushes(WriteData *wd, ListBase *idbase)
+static void write_brush(WriteData *wd, Brush *brush)
{
- 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);
- write_iddata(wd, &brush->id);
+ 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->curve) {
+ write_curvemapping(wd, brush->curve);
+ }
+ if (brush->gradient) {
+ writestruct(wd, DATA, ColorBand, 1, brush->gradient);
}
}
}
-static void write_palettes(WriteData *wd, ListBase *idbase)
+static void write_palette(WriteData *wd, Palette *palette)
{
- Palette *palette;
-
- 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);
- write_iddata(wd, &palette->id);
+ if (palette->id.us > 0 || wd->current) {
+ PaletteColor *color;
+ 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);
}
}
}
-static void write_paintcurves(WriteData *wd, ListBase *idbase)
+static void write_paintcurve(WriteData *wd, PaintCurve *pc)
{
- PaintCurve *pc;
-
- for (pc = idbase->first; pc; pc = pc->id.next) {
- if (pc->id.us > 0 || wd->current) {
- writestruct(wd, ID_PC, PaintCurve, 1, pc);
- write_iddata(wd, &pc->id);
+ if (pc->id.us > 0 || wd->current) {
+ writestruct(wd, ID_PC, PaintCurve, 1, pc);
+ write_iddata(wd, &pc->id);
- writestruct(wd, DATA, PaintCurvePoint, pc->tot_points, pc->points);
- }
+ writestruct(wd, DATA, PaintCurvePoint, pc->tot_points, pc->points);
}
}
@@ -3503,103 +3290,85 @@ static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction
}
}
-static void write_movieclips(WriteData *wd, ListBase *idbase)
+static void write_movieclip(WriteData *wd, MovieClip *clip)
{
- MovieClip *clip;
-
- clip = idbase->first;
- while (clip) {
- if (clip->id.us > 0 || wd->current) {
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
+ if (clip->id.us > 0 || wd->current) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
- writestruct(wd, ID_MC, MovieClip, 1, clip);
- write_iddata(wd, &clip->id);
+ writestruct(wd, ID_MC, MovieClip, 1, clip);
+ write_iddata(wd, &clip->id);
- if (clip->adt) {
- write_animdata(wd, 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);
+ write_movieTracks(wd, &tracking->tracks);
+ write_moviePlaneTracks(wd, &tracking->plane_tracks);
+ write_movieReconstruction(wd, &tracking->reconstruction);
- object = tracking->objects.first;
- while (object) {
- writestruct(wd, DATA, MovieTrackingObject, 1, object);
+ object = tracking->objects.first;
+ while (object) {
+ writestruct(wd, DATA, MovieTrackingObject, 1, object);
- write_movieTracks(wd, &object->tracks);
- write_moviePlaneTracks(wd, &object->plane_tracks);
- write_movieReconstruction(wd, &object->reconstruction);
+ 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;
}
-
- mywrite_flush(wd);
}
-static void write_masks(WriteData *wd, ListBase *idbase)
+static void write_mask(WriteData *wd, Mask *mask)
{
- Mask *mask;
-
- mask = idbase->first;
- while (mask) {
- if (mask->id.us > 0 || wd->current) {
- MaskLayer *masklay;
+ if (mask->id.us > 0 || wd->current) {
+ MaskLayer *masklay;
- writestruct(wd, ID_MSK, Mask, 1, mask);
- write_iddata(wd, &mask->id);
+ writestruct(wd, ID_MSK, Mask, 1, mask);
+ write_iddata(wd, &mask->id);
- if (mask->adt) {
- write_animdata(wd, mask->adt);
- }
+ if (mask->adt) {
+ write_animdata(wd, mask->adt);
+ }
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
- MaskLayerShape *masklay_shape;
+ 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;
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ int i;
- void *points_deform = spline->points_deform;
- spline->points_deform = NULL;
+ 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;
+ spline->points_deform = points_deform;
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &spline->points[i];
+ 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);
}
}
-
- mask = mask->id.next;
}
-
- mywrite_flush(wd);
}
static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers)
@@ -3856,48 +3625,39 @@ static void write_linestyle_geometry_modifiers(WriteData *wd, ListBase *modifier
}
}
-static void write_linestyles(WriteData *wd, ListBase *idbase)
+static void write_linestyle(WriteData *wd, FreestyleLineStyle *linestyle)
{
- FreestyleLineStyle *linestyle;
- 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);
- write_iddata(wd, &linestyle->id);
+ 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);
- }
+ 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]);
- }
- }
- if (linestyle->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, linestyle->nodetree);
- write_nodetree(wd, linestyle->nodetree);
+ 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 (int 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);
+ write_nodetree_nolib(wd, linestyle->nodetree);
+ }
}
}
-static void write_cachefiles(WriteData *wd, ListBase *idbase)
+static void write_cachefile(WriteData *wd, CacheFile *cache_file)
{
- CacheFile *cache_file;
-
- for (cache_file = idbase->first; cache_file; cache_file = cache_file->id.next) {
- if (cache_file->id.us > 0 || wd->current) {
- writestruct(wd, ID_CF, CacheFile, 1, cache_file);
+ if (cache_file->id.us > 0 || wd->current) {
+ writestruct(wd, ID_CF, CacheFile, 1, cache_file);
- if (cache_file->adt) {
- write_animdata(wd, cache_file->adt);
- }
+ if (cache_file->adt) {
+ write_animdata(wd, cache_file->adt);
}
}
}
@@ -3911,7 +3671,6 @@ static void write_libraries(WriteData *wd, Main *main)
bool found_one;
for (; main; main = main->next) {
-
a = tot = set_listbasepointers(main, lbarray);
/* test: is lib being used */
@@ -3920,16 +3679,13 @@ static void write_libraries(WriteData *wd, Main *main)
}
else {
found_one = false;
- while (tot--) {
+ while (!found_one && 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;
- }
}
}
@@ -4068,38 +3824,134 @@ static bool write_file_handle(
* avoid thumbnail detecting changes because of this. */
mywrite_flush(wd);
- write_windowmanagers(wd, &mainvar->wm);
- write_screens(wd, &mainvar->screen);
- write_movieclips(wd, &mainvar->movieclip);
- 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_materials(wd, &mainvar->mat);
- 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_linestyles(wd, &mainvar->linestyle);
- write_cachefiles(wd, &mainvar->cachefiles);
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a = set_listbasepointers(mainvar, lbarray);
+ while (a--) {
+ ID *id = lbarray[a]->first;
+
+ if (id && GS(id->name) == ID_LI) {
+ continue; /* Libraries are handled separately below. */
+ }
+
+ for (; id; id = id->next) {
+ /* We should never attempt to write non-regular IDs (i.e. all kind of temp/runtime ones). */
+ BLI_assert((id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0);
+
+ switch ((ID_Type)GS(id->name)) {
+ case ID_WM:
+ write_windowmanager(wd, (wmWindowManager *)id);
+ break;
+ case ID_SCR:
+ write_screen(wd, (bScreen *)id);
+ break;
+ case ID_MC:
+ write_movieclip(wd, (MovieClip *)id);
+ break;
+ case ID_MSK:
+ write_mask(wd, (Mask *)id);
+ break;
+ case ID_SCE:
+ write_scene(wd, (Scene *)id);
+ break;
+ case ID_CU:
+ write_curve(wd, (Curve *)id);
+ break;
+ case ID_MB:
+ write_mball(wd, (MetaBall *)id);
+ break;
+ case ID_IM:
+ write_image(wd, (Image *)id);
+ break;
+ case ID_CA:
+ write_camera(wd, (Camera *)id);
+ break;
+ case ID_LA:
+ write_lamp(wd, (Lamp *)id);
+ break;
+ case ID_LT:
+ write_lattice(wd, (Lattice *)id);
+ break;
+ case ID_VF:
+ write_vfont(wd, (VFont *)id);
+ break;
+ case ID_KE:
+ write_key(wd, (Key *)id);
+ break;
+ case ID_WO:
+ write_world(wd, (World *)id);
+ break;
+ case ID_TXT:
+ write_text(wd, (Text *)id);
+ break;
+ case ID_SPK:
+ write_speaker(wd, (Speaker *)id);
+ break;
+ case ID_SO:
+ write_sound(wd, (bSound *)id);
+ break;
+ case ID_GR:
+ write_group(wd, (Group *)id);
+ break;
+ case ID_AR:
+ write_armature(wd, (bArmature *)id);
+ break;
+ case ID_AC:
+ write_action(wd, (bAction *)id);
+ break;
+ case ID_OB:
+ write_object(wd, (Object *)id);
+ break;
+ case ID_MA:
+ write_material(wd, (Material *)id);
+ break;
+ case ID_TE:
+ write_texture(wd, (Tex *)id);
+ break;
+ case ID_ME:
+ write_mesh(wd, (Mesh *)id);
+ break;
+ case ID_PA:
+ write_particlesettings(wd, (ParticleSettings *)id);
+ break;
+ case ID_NT:
+ write_nodetree(wd, (bNodeTree *)id);
+ break;
+ case ID_BR:
+ write_brush(wd, (Brush *)id);
+ break;
+ case ID_PAL:
+ write_palette(wd, (Palette *)id);
+ break;
+ case ID_PC:
+ write_paintcurve(wd, (PaintCurve *)id);
+ break;
+ case ID_GD:
+ write_gpencil(wd, (bGPdata *)id);
+ break;
+ case ID_LS:
+ write_linestyle(wd, (FreestyleLineStyle *)id);
+ break;
+ case ID_CF:
+ write_cachefile(wd, (CacheFile *)id);
+ break;
+ case ID_LI:
+ /* Do nothing, handled below - and should never be reached. */
+ BLI_assert(0);
+ break;
+ case ID_IP:
+ /* Do nothing, deprecated. */
+ break;
+ default:
+ /* Should never be reached. */
+ BLI_assert(0);
+ break;
+ }
+ }
+
+ mywrite_flush(wd);
+ }
+
+ /* Special handling, operating over split Mains... */
write_libraries(wd, mainvar->next);
/* So changes above don't cause a 'DNA1' to be detected as changed on undo. */
diff --git a/source/blender/blentranslation/CMakeLists.txt b/source/blender/blentranslation/CMakeLists.txt
index a3e85344027..320a784ea25 100644
--- a/source/blender/blentranslation/CMakeLists.txt
+++ b/source/blender/blentranslation/CMakeLists.txt
@@ -60,3 +60,7 @@ if(WIN32)
endif()
blender_add_lib(bf_blentranslation "${SRC}" "${INC}" "${INC_SYS}")
+
+if(WITH_INTERNATIONAL)
+ add_subdirectory(msgfmt)
+endif()
diff --git a/source/blender/quicktime/CMakeLists.txt b/source/blender/blentranslation/msgfmt/CMakeLists.txt
index f853c35457f..d2cb6f5a03b 100644
--- a/source/blender/quicktime/CMakeLists.txt
+++ b/source/blender/blentranslation/msgfmt/CMakeLists.txt
@@ -14,49 +14,37 @@
# 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) 2006, Blender Foundation
+# The Original Code is Copyright (C) 2017, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
-# Contributor(s): Jacques Beaurain.
+# Contributor(s): Bastien Montagne.
#
# ***** END GPL LICENSE BLOCK *****
-set(INC
- .
- ../avi
- ../blenkernel
- ../blenlib
- ../imbuf
- ../imbuf/intern
- ../makesdna
- ../makesrna
- ../render/extern/include
- ../windowmanager
- ../../../intern/guardedalloc
-)
+# -----------------------------------------------------------------------------
+# Build msgfmt executable
-set(INC_SYS
- ${QUICKTIME_INCLUDE_DIRS}
+blender_include_dirs(
+ ../../../../intern/guardedalloc
+ ../../blenlib
)
set(SRC
- apple/qtkit_import.m
- apple/qtkit_export.m
-
- quicktime_export.h
- quicktime_import.h
+ msgfmt.c
)
-add_definitions(-DWITH_QUICKTIME)
+add_cc_flags_custom_test(msgfmt)
+
+add_executable(msgfmt ${SRC})
-if(WITH_AUDASPACE)
- add_definitions(${AUDASPACE_DEFINITIONS})
+target_link_libraries(msgfmt bf_blenlib)
+target_link_libraries(msgfmt bf_intern_guardedalloc)
- list(APPEND INC_SYS
- ${AUDASPACE_C_INCLUDE_DIRS}
- )
+if(WIN32)
+ target_link_libraries(msgfmt bf_intern_utfconv)
endif()
-blender_add_lib(bf_quicktime "${SRC}" "${INC}" "${INC_SYS}")
+target_link_libraries(msgfmt ${ZLIB_LIBRARIES})
+target_link_libraries(msgfmt ${PLATFORM_LINKLIBS})
diff --git a/source/blender/blentranslation/msgfmt/msgfmt.c b/source/blender/blentranslation/msgfmt/msgfmt.c
new file mode 100644
index 00000000000..3abce7b1d3f
--- /dev/null
+++ b/source/blender/blentranslation/msgfmt/msgfmt.c
@@ -0,0 +1,467 @@
+/*
+ * ***** 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) 2017 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/*
+ * Based on C++ version by Sergey Sharybin <sergey.vfx@gmail.com>.
+ * Based on Python script msgfmt.py from Python source code tree, which was written by
+ * Martin v. Löwis <loewis@informatik.hu-berlin.de>
+ *
+ * Generate binary message catalog from textual translation description.
+ *
+ * This program converts a textual Uniforum-style message catalog (.po file) into a binary GNU catalog (.mo file).
+ * This is essentially the same function as the GNU msgfmt program, however, it is a simpler implementation.
+ *
+ * Usage: msgfmt input.po output.po
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_dynstr.h"
+#include "BLI_fileops.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* Stupid stub necessary because some BLI files includes winstuff.h, which uses G a bit... */
+#ifdef WIN32
+ typedef struct Global {
+ void *dummy;
+ } Global;
+
+ Global G;
+#endif
+
+
+/* We cannot use NULL char until ultimate step, would give nightmare to our C string processing...
+ * Using one of the UTF-8 invalid bytes (as per our BLI string_utf8.c) */
+#define NULLSEP_STR "\xff"
+#define NULLSEP_CHR '\xff'
+
+typedef enum {
+ SECTION_NONE = 0,
+ SECTION_CTX = 1,
+ SECTION_ID = 2,
+ SECTION_STR = 3,
+} eSectionType;
+
+typedef struct Message {
+ DynStr *ctxt;
+ DynStr *id;
+ DynStr *str;
+
+ bool is_fuzzy;
+} Message;
+
+static char *trim(char *str)
+{
+ const size_t len = strlen(str);
+ size_t i;
+
+ if (len == 0) {
+ return str;
+ }
+
+ for (i = 0; i < len && ELEM(str[0], ' ', '\t', '\n'); str++, i++);
+
+ char *end = &str[len - 1 - i];
+ for (i = len; i > 0 && ELEM(end[0], ' ', '\t', '\n'); end--, i--);
+ end[1] = '\0';
+
+ return str;
+}
+
+static char *unescape(char *str)
+{
+ char *curr, *next;
+ for (curr = next = str; next[0] != '\0'; curr++, next++) {
+ if (next[0] == '\\') {
+ switch (next[1]) {
+ case '\0':
+ /* Get rid of trailing escape char... */
+ curr--;
+ break;
+ case '\\':
+ *curr = '\\';
+ next++;
+ break;
+ case 'n':
+ *curr = '\n';
+ next++;
+ break;
+ case 't':
+ *curr = '\t';
+ next++;
+ break;
+ default:
+ /* Get rid of useless escape char. */
+ next++;
+ *curr = *next;
+ }
+ }
+ else if (curr != next) {
+ *curr = *next;
+ }
+ }
+ *curr = '\0';
+
+ if (str[0] == '"' && *(curr - 1) == '"') {
+ *(curr - 1) = '\0';
+ return str + 1;
+ }
+ return str;
+}
+
+static int qsort_str_cmp(const void *a, const void *b)
+{
+ return strcmp(*(const char **)a, *(const char **)b);
+}
+
+static char **get_keys_sorted(GHash *messages, const uint32_t num_keys)
+{
+ GHashIterator iter;
+
+ char **keys = MEM_mallocN(sizeof(*keys) * num_keys, __func__);
+ char **k = keys;
+
+ GHASH_ITER(iter, messages) {
+ *k = BLI_ghashIterator_getKey(&iter);
+ k++;
+ }
+
+ qsort(keys, num_keys, sizeof(*keys), qsort_str_cmp);
+
+ return keys;
+}
+
+BLI_INLINE size_t uint32_to_bytes(const int value, char *bytes)
+{
+ size_t i;
+ for (i = 0; i < sizeof(value); i++) {
+ bytes[i] = (char) ((value >> ((int)i * 8)) & 0xff);
+ }
+ return i;
+}
+
+BLI_INLINE size_t msg_to_bytes(char *msg, char *bytes, uint32_t size)
+{
+ /* Note that we also perform replacing of our NULLSEP placeholder by real NULL char... */
+ size_t i;
+ for (i = 0; i < size; i++, msg++, bytes++) {
+ *bytes = (*msg == NULLSEP_CHR) ? '\0' : *msg;
+ }
+ return i;
+}
+
+typedef struct Offset {
+ uint32_t key_offset, key_len, val_offset, val_len;
+} Offset;
+
+/* Return the generated binary output. */
+static char *generate(GHash *messages, size_t *r_output_size) {
+ const uint32_t num_keys = BLI_ghash_size(messages);
+
+ /* Get list of sorted keys. */
+ char **keys = get_keys_sorted(messages, num_keys);
+ char **vals = MEM_mallocN(sizeof(*vals) * num_keys, __func__);
+ uint32_t tot_keys_len = 0;
+ uint32_t tot_vals_len = 0;
+
+ Offset *offsets = MEM_mallocN(sizeof(*offsets) * num_keys, __func__);
+
+ for (int i = 0; i < num_keys; i++) {
+ Offset *off = &offsets[i];
+
+ vals[i] = BLI_ghash_lookup(messages, keys[i]);
+
+ /* For each string, we need size and file offset.
+ * Each string is NULL terminated; the NULL does not count into the size. */
+ off->key_offset = tot_keys_len;
+ off->key_len = (uint32_t)strlen(keys[i]);
+ tot_keys_len += off->key_len + 1;
+
+ off->val_offset = tot_vals_len;
+ off->val_len = (uint32_t)strlen(vals[i]);
+ tot_vals_len += off->val_len + 1;
+ }
+
+ /* The header is 7 32-bit unsigned integers. then comes the keys index table, then the values index table. */
+ const uint32_t idx_keystart = 7 * 4;
+ const uint32_t idx_valstart = idx_keystart + 8 * num_keys;
+ /* We don't use hash tables, so the keys start right after the index tables. */
+ const uint32_t keystart = idx_valstart + 8 * num_keys;
+ /* and the values start after the keys */
+ const uint32_t valstart = keystart + tot_keys_len;
+
+ /* Final buffer representing the binary MO file. */
+ *r_output_size = valstart + tot_vals_len;
+ char *output = MEM_mallocN(*r_output_size, __func__);
+ char *h = output;
+ char *ik = output + idx_keystart;
+ char *iv = output + idx_valstart;
+ char *k = output + keystart;
+ char *v = output + valstart;
+
+ h += uint32_to_bytes(0x950412de, h); /* Magic */
+ h += uint32_to_bytes(0x0, h); /* Version */
+ h += uint32_to_bytes(num_keys, h); /* Number of entries */
+ h += uint32_to_bytes(idx_keystart, h); /* Start of key index */
+ h += uint32_to_bytes(idx_valstart, h); /* Start of value index */
+ h += uint32_to_bytes(0, h); /* Size of hash table */
+ h += uint32_to_bytes(0, h); /* Offset of hash table */
+
+ BLI_assert(h == ik);
+
+ for (int i = 0; i < num_keys; i++) {
+ Offset *off = &offsets[i];
+
+ /* The index table first has the list of keys, then the list of values.
+ * Each entry has first the size of the string, then the file offset. */
+ ik += uint32_to_bytes(off->key_len, ik);
+ ik += uint32_to_bytes(off->key_offset + keystart, ik);
+ iv += uint32_to_bytes(off->val_len, iv);
+ iv += uint32_to_bytes(off->val_offset + valstart, iv);
+
+ k += msg_to_bytes(keys[i], k, off->key_len + 1);
+ v += msg_to_bytes(vals[i], v, off->val_len + 1);
+ }
+
+ BLI_assert(ik == output + idx_valstart);
+ BLI_assert(iv == output + keystart);
+ BLI_assert(k == output + valstart);
+
+ MEM_freeN(keys);
+ MEM_freeN(vals);
+ MEM_freeN(offsets);
+
+ return output;
+}
+
+/* Add a non-fuzzy translation to the dictionary. */
+static void add(GHash *messages, MemArena *memarena, const Message *msg)
+{
+ const size_t msgctxt_len = (size_t)BLI_dynstr_get_len(msg->ctxt);
+ const size_t msgid_len = (size_t)BLI_dynstr_get_len(msg->id);
+ const size_t msgstr_len = (size_t)BLI_dynstr_get_len(msg->str);
+ const size_t msgkey_len = msgid_len + ((msgctxt_len == 0) ? 0 : msgctxt_len + 1);
+
+ if (!msg->is_fuzzy && msgstr_len != 0) {
+ char *msgkey = BLI_memarena_alloc(memarena, sizeof(*msgkey) * (msgkey_len + 1));
+ char *msgstr = BLI_memarena_alloc(memarena, sizeof(*msgstr) * (msgstr_len + 1));
+
+ if (msgctxt_len != 0) {
+ BLI_dynstr_get_cstring_ex(msg->ctxt, msgkey);
+ msgkey[msgctxt_len] = '\x04'; /* Context/msgid separator */
+ BLI_dynstr_get_cstring_ex(msg->id, &msgkey[msgctxt_len + 1]);
+ }
+ else {
+ BLI_dynstr_get_cstring_ex(msg->id, msgkey);
+ }
+
+ BLI_dynstr_get_cstring_ex(msg->str, msgstr);
+
+ BLI_ghash_insert(messages, msgkey, msgstr);
+ }
+}
+
+
+static void clear(Message *msg)
+{
+ BLI_dynstr_clear(msg->ctxt);
+ BLI_dynstr_clear(msg->id);
+ BLI_dynstr_clear(msg->str);
+ msg->is_fuzzy = false;
+}
+
+static int make(const char *input_file_name, const char *output_file_name)
+{
+ GHash *messages = BLI_ghash_new(BLI_ghashutil_strhash_p_murmur, BLI_ghashutil_strcmp, __func__);
+ MemArena *msgs_memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ const char *msgctxt_kw = "msgctxt";
+ const char *msgid_kw = "msgid";
+ const char *msgid_plural_kw = "msgid_plural";
+ const char *msgstr_kw = "msgstr";
+ const size_t msgctxt_len = strlen(msgctxt_kw);
+ const size_t msgid_len = strlen(msgid_kw);
+ const size_t msgid_plural_len = strlen(msgid_plural_kw);
+ const size_t msgstr_len = strlen(msgstr_kw);
+
+ /* Note: For now, we assume file encoding is always utf-8. */
+
+ eSectionType section = SECTION_NONE;
+ bool is_plural = false;
+
+ Message msg = {
+ .ctxt = BLI_dynstr_new_memarena(),
+ .id = BLI_dynstr_new_memarena(),
+ .str = BLI_dynstr_new_memarena(),
+ .is_fuzzy = false,
+ };
+
+ LinkNode *input_file_lines = BLI_file_read_as_lines(input_file_name);
+ LinkNode *ifl = input_file_lines;
+
+ /* Parse the catalog. */
+ for (int lno = 1; ifl; ifl = ifl->next, lno++) {
+ char *l = ifl->link;
+ const bool is_comment = (l[0] == '#');
+ /* If we get a comment line after a msgstr, this is a new entry. */
+ if (is_comment) {
+ if (section == SECTION_STR) {
+ add(messages, msgs_memarena, &msg);
+ clear(&msg);
+ section = SECTION_NONE;
+ }
+ /* Record a fuzzy mark. */
+ if (l[1] == ',' && strstr(l, "fuzzy") != NULL) {
+ msg.is_fuzzy = true;
+ }
+ /* Skip comments */
+ continue;
+ }
+ if (strstr(l, msgctxt_kw) == l) {
+ if (section == SECTION_STR) {
+ /* New message, output previous section. */
+ add(messages, msgs_memarena, &msg);
+ }
+ if (!ELEM(section, SECTION_NONE, SECTION_STR)) {
+ printf("msgctxt not at start of new message on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ section = SECTION_CTX;
+ l = l + msgctxt_len;
+ clear(&msg);
+ }
+ else if (strstr(l, msgid_plural_kw) == l) {
+ /* This is a message with plural forms. */
+ if (section != SECTION_ID) {
+ printf("msgid_plural not preceeded by msgid on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ l = l + msgid_plural_len;
+ BLI_dynstr_append(msg.id, NULLSEP_STR); /* separator of singular and plural */
+ is_plural = true;
+ }
+ else if (strstr(l, msgid_kw) == l) {
+ if (section == SECTION_STR) {
+ add(messages, msgs_memarena, &msg);
+ }
+ if (section != SECTION_CTX) {
+ clear(&msg);
+ }
+ section = SECTION_ID;
+ l = l + msgid_len;
+ is_plural = false;
+ }
+ else if (strstr(l, msgstr_kw) == l) {
+ l = l + msgstr_len;
+ // Now we are in a msgstr section
+ section = SECTION_STR;
+ if (l[0] == '[') {
+ if (!is_plural) {
+ printf("plural without msgid_plural on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ if ((l = strchr(l, ']')) == NULL) {
+ printf("Syntax error on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ if (BLI_dynstr_get_len(msg.str) != 0) {
+ BLI_dynstr_append(msg.str, NULLSEP_STR); /* Separator of the various plural forms. */
+ }
+ }
+ else {
+ if (is_plural) {
+ printf("indexed msgstr required for plural on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ }
+ }
+ /* Skip empty lines. */
+ l = trim(l);
+ if (l[0] == '\0') {
+ if (section == SECTION_STR) {
+ add(messages, msgs_memarena, &msg);
+ clear(&msg);
+ }
+ section = SECTION_NONE;
+ continue;
+ }
+ l = unescape(l);
+ if (section == SECTION_CTX) {
+ BLI_dynstr_append(msg.ctxt, l);
+ }
+ else if (section == SECTION_ID) {
+ BLI_dynstr_append(msg.id, l);
+ }
+ else if (section == SECTION_STR) {
+ BLI_dynstr_append(msg.str, l);
+ }
+ else {
+ printf("Syntax error on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ }
+ /* Add last entry */
+ if (section == SECTION_STR) {
+ add(messages, msgs_memarena, &msg);
+ }
+
+ BLI_dynstr_free(msg.ctxt);
+ BLI_dynstr_free(msg.id);
+ BLI_dynstr_free(msg.str);
+ BLI_file_free_lines(input_file_lines);
+
+ /* Compute output */
+ size_t output_size;
+ char *output = generate(messages, &output_size);
+
+ FILE *fp = BLI_fopen(output_file_name, "wb");
+ fwrite(output, 1, output_size, fp);
+ fclose(fp);
+
+ MEM_freeN(output);
+ BLI_ghash_free(messages, NULL, NULL);
+ BLI_memarena_free(msgs_memarena);
+
+ return EXIT_SUCCESS;
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 3) {
+ printf("Usage: %s <input.po> <output.mo>\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+ const char *input_file = argv[1];
+ const char *output_file = argv[2];
+
+ return make(input_file, output_file);
+}
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 30fefe37f0e..ea24da86626 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -152,6 +152,8 @@ set(SRC
tools/bmesh_path_region.h
tools/bmesh_region_match.c
tools/bmesh_region_match.h
+ tools/bmesh_separate.c
+ tools/bmesh_separate.h
tools/bmesh_triangulate.c
tools/bmesh_triangulate.h
tools/bmesh_wireframe.c
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index f29d280d071..b84a3d5e559 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -192,9 +192,10 @@
*
* These conventions should be used throughout the bmesh module.
*
- * - ``BM_***()`` - High level BMesh API function for use anywhere.
- * - ``bmesh_***()`` - Low level API function.
+ * - ``bmesh_kernel_*()`` - Low level API, for primitive functions that others are built ontop of.
+ * - ``bmesh_***()`` - Low level API function.
* - ``bm_***()`` - 'static' functions, not apart of the API at all, but use prefix since they operate on BMesh data.
+ * - ``BM_***()`` - High level BMesh API function for use anywhere.
* - ``BMO_***()`` - High level operator API function for use anywhere.
* - ``bmo_***()`` - Low level / internal operator API functions.
* - ``_bm_***()`` - Functions which are called via macros only.
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 104df625ee6..64a5cad812a 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -225,7 +225,7 @@ 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;
+ uint use_toolflags : 1;
int toolflag_index;
struct BMOperator *currentop;
@@ -382,7 +382,7 @@ typedef bool (*BMLoopFilterFunc)(const BMLoop *, void *user_data);
(assert(offset != -1), *((float *)((char *)(ele)->head.data + (offset))))
#define BM_ELEM_CD_GET_FLOAT_AS_UCHAR(ele, offset) \
- (assert(offset != -1), (unsigned char)(BM_ELEM_CD_GET_FLOAT(ele, offset) * 255.0f))
+ (assert(offset != -1), (uchar)(BM_ELEM_CD_GET_FLOAT(ele, offset) * 255.0f))
/*forward declarations*/
diff --git a/source/blender/bmesh/bmesh_tools.h b/source/blender/bmesh/bmesh_tools.h
index 23212dd085e..a537c3b872c 100644
--- a/source/blender/bmesh/bmesh_tools.h
+++ b/source/blender/bmesh/bmesh_tools.h
@@ -43,6 +43,7 @@ extern "C" {
#include "tools/bmesh_path.h"
#include "tools/bmesh_path_region.h"
#include "tools/bmesh_region_match.h"
+#include "tools/bmesh_separate.h"
#include "tools/bmesh_triangulate.h"
#ifdef __cplusplus
diff --git a/source/blender/bmesh/intern/bmesh_callback_generic.c b/source/blender/bmesh/intern/bmesh_callback_generic.c
index 913255bfb33..e9304e8536f 100644
--- a/source/blender/bmesh/intern/bmesh_callback_generic.c
+++ b/source/blender/bmesh/intern/bmesh_callback_generic.c
@@ -32,7 +32,7 @@
bool BM_elem_cb_check_hflag_ex(BMElem *ele, void *user_data)
{
- const unsigned int hflag_pair = GET_INT_FROM_POINTER(user_data);
+ const uint hflag_pair = GET_INT_FROM_POINTER(user_data);
const char hflag_p = (hflag_pair & 0xff);
const char hflag_n = (hflag_pair >> 8);
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index 132a7ccd4fa..f8ecbe1756b 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -154,7 +154,7 @@ void BM_face_copy_shared(
if (l_other && l_other != l_iter) {
BMLoop *l_src[2];
BMLoop *l_dst[2] = {l_iter, l_iter->next};
- unsigned int j;
+ uint j;
if (l_other->v == l_iter->v) {
l_src[0] = l_other;
@@ -311,7 +311,7 @@ BMFace *BM_face_create_ngon_verts(
const bool calc_winding, const bool create_edges)
{
BMEdge **edge_arr = BLI_array_alloca(edge_arr, len);
- unsigned int winding[2] = {0, 0};
+ uint winding[2] = {0, 0};
int i, i_prev = len - 1;
BMVert *v_winding[2] = {vert_arr[i_prev], vert_arr[0]};
@@ -387,15 +387,11 @@ BMFace *BM_face_create_ngon_verts(
*
* \note Since this is a vcloud there is no direction.
*/
-BMFace *BM_face_create_ngon_vcloud(
- BMesh *bm, BMVert **vert_arr, int len,
- const BMFace *f_example, const eBMCreateFlag create_flag)
+void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
{
struct SortIntByFloat *vang = BLI_array_alloca(vang, len);
BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len);
- BMFace *f;
-
float totv_inv = 1.0f / (float)len;
int i = 0;
@@ -470,26 +466,9 @@ BMFace *BM_face_create_ngon_vcloud(
/* now calculate every points angle around the normal (signed) */
for (i = 0; i < len; i++) {
- float co[3];
- float proj_vec[3];
- float angle;
-
- /* center relative vec */
- sub_v3_v3v3(co, vert_arr[i]->co, cent);
-
- /* align to plane */
- project_v3_v3v3(proj_vec, co, nor);
- sub_v3_v3(co, proj_vec);
-
- /* now 'co' is valid - we can compare its angle against the far vec */
- angle = angle_v3v3(far_vec, co);
-
- if (dot_v3v3(co, sign_vec) < 0.0f) {
- angle = -angle;
- }
-
- vang[i].sort_value = angle;
+ vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor);
vang[i].data = i;
+ vert_arr_map[i] = vert_arr[i];
}
/* sort by angle and magic! - we have our ngon */
@@ -497,14 +476,9 @@ BMFace *BM_face_create_ngon_vcloud(
/* --- */
- /* create edges and find the winding (if faces are attached to any existing edges) */
for (i = 0; i < len; i++) {
- vert_arr_map[i] = vert_arr[vang[i].data];
+ vert_arr[i] = vert_arr_map[vang[i].data];
}
-
- f = BM_face_create_ngon_verts(bm, vert_arr_map, len, f_example, create_flag, true, true);
-
- return f;
}
/*************************************************************/
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index 9c6483de42b..a52a17cd2f3 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -34,6 +34,9 @@ bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len);
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len);
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len);
+/* sort before creation */
+void BM_verts_sort_radial_plane(BMVert **vert_arr, int len);
+
BMFace *BM_face_create_quad_tri(
BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
const BMFace *f_example, const eBMCreateFlag create_flag);
@@ -50,10 +53,6 @@ BMFace *BM_face_create_ngon_verts(
const BMFace *f_example, const eBMCreateFlag create_flag,
const bool calc_winding, const bool create_edges);
-BMFace *BM_face_create_ngon_vcloud(
- BMesh *bm, BMVert **vert_arr, int len,
- const BMFace *f_example, const eBMCreateFlag create_flag);
-
void BM_elem_attrs_copy_ex(
BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v,
const char hflag_mask);
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index d1178a198dc..c7ff93cf504 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -32,7 +32,7 @@
#include "BLI_array.h"
#include "BLI_alloca.h"
#include "BLI_linklist_stack.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BLT_translation.h"
@@ -1021,7 +1021,7 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l)
* \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
* (use when flipping normals, disable when mirroring, eg: symmetrize).
*/
-void bmesh_loop_reverse(
+void bmesh_kernel_loop_reverse(
BMesh *bm, BMFace *f,
const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
{
@@ -1438,7 +1438,7 @@ static BMFace *bm_face_create__sfme(BMesh *bm, BMFace *f_example)
*
* \return A BMFace pointer
*/
-BMFace *bmesh_sfme(
+BMFace *bmesh_kernel_split_face_make_edge(
BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2,
BMLoop **r_l,
#ifdef USE_BMESH_HOLES
@@ -1584,7 +1584,7 @@ BMFace *bmesh_sfme(
*
* \return The newly created BMVert pointer.
*/
-BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
+BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
{
BMLoop *l_next;
BMEdge *e_new;
@@ -1766,7 +1766,7 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
* faces with just 2 edges. It is up to the caller to decide what to do with
* these faces.
*/
-BMEdge *bmesh_jekv(
+BMEdge *bmesh_kernel_join_edge_kill_vert(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
const bool do_del, const bool check_edge_double,
const bool kill_degenerate_faces)
@@ -1920,7 +1920,7 @@ BMEdge *bmesh_jekv(
*
* Collapse an edge, merging surrounding data.
*
- * Unlike #BM_vert_collapse_edge & #bmesh_jekv which only handle 2 valence verts,
+ * Unlike #BM_vert_collapse_edge & #bmesh_kernel_join_edge_kill_vert which only handle 2 valence verts,
* this can handle any number of connected edges/faces.
*
* <pre>
@@ -1932,7 +1932,7 @@ BMEdge *bmesh_jekv(
* +-+-+-+ +-+-+-+
* </pre>
*/
-BMVert *bmesh_jvke(
+BMVert *bmesh_kernel_join_vert_kill_edge(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
const bool do_del, const bool check_edge_double,
const bool kill_degenerate_faces)
@@ -2035,7 +2035,7 @@ BMVert *bmesh_jvke(
* In the example A, faces \a f1 and \a f2 are joined by a single edge,
* and the euler can safely be used.
* In example B however, \a f1 and \a f2 are joined by multiple edges and will produce an error.
- * The caller in this case should call #bmesh_jekv on the extra edges
+ * The caller in this case should call #bmesh_kernel_join_edge_kill_vert on the extra edges
* before attempting to fuse \a f1 and \a f2.
*
* \note The order of arguments decides whether or not certain per-face attributes are present
@@ -2044,7 +2044,7 @@ BMVert *bmesh_jvke(
*
* \return A BMFace pointer
*/
-BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
+BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
{
BMLoop *l_iter, *l_f1 = NULL, *l_f2 = NULL;
int newlen = 0, i, f1len = 0, f2len = 0;
@@ -2249,7 +2249,7 @@ bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
}
-/** \name BM_vert_separate, bmesh_vert_separate and friends
+/** \name BM_vert_separate, bmesh_kernel_vert_separate and friends
* \{ */
/* BM_edge_face_count(e) >= 1 */
@@ -2269,7 +2269,7 @@ BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e)
*
* \return Success
*/
-void bmesh_vert_separate(
+void bmesh_kernel_vert_separate(
BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
const bool copy_select)
{
@@ -2385,7 +2385,7 @@ void bmesh_vert_separate(
*
* Takes a list of edges, which have been split from their original.
*
- * Any edges which failed to split off in #bmesh_vert_separate will be merged back into the original edge.
+ * Any edges which failed to split off in #bmesh_kernel_vert_separate will be merged back into the original edge.
*
* \param edges_separate
* A list-of-lists, each list is from a single original edge (the first edge is the original),
@@ -2398,27 +2398,33 @@ void bmesh_vert_separate(
* \note this function looks like it could become slow,
* but in common cases its only going to iterate a few times.
*/
-static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
+static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
{
do {
LinkNode *n_orig = edges_separate->link;
do {
- BMEdge *e_orig = n_orig->link;
+ LinkNode *n_prev = n_orig;
LinkNode *n_step = n_orig->next;
+ BMEdge *e_orig = n_orig->link;
do {
BMEdge *e = n_step->link;
BLI_assert(e != e_orig);
- if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2)) {
- BM_edge_splice(bm, e_orig, e);
+ if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2) &&
+ BM_edge_splice(bm, e_orig, e))
+ {
+ /* don't visit again */
+ n_prev->next = n_step->next;
}
- } while ((n_step = n_step->next));
+ } while ((void)
+ (n_prev = n_step),
+ (n_step = n_step->next));
} while ((n_orig = n_orig->next) && n_orig->next);
} while ((edges_separate = edges_separate->next));
}
/**
- * High level function which wraps both #bmesh_vert_separate and #bmesh_edge_separate
+ * High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate
*/
void BM_vert_separate(
BMesh *bm, BMVert *v,
@@ -2435,7 +2441,7 @@ void BM_vert_separate(
LinkNode *edges_orig = NULL;
do {
BMLoop *l_sep = e->l;
- bmesh_edge_separate(bm, e, l_sep, copy_select);
+ bmesh_kernel_edge_separate(bm, e, l_sep, copy_select);
BLI_linklist_prepend_alloca(&edges_orig, l_sep->e);
BLI_assert(e != l_sep->e);
} while (bm_edge_supports_separate(e));
@@ -2444,10 +2450,10 @@ void BM_vert_separate(
}
}
- bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
+ bmesh_kernel_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
if (edges_separate) {
- bmesh_vert_separate__cleanup(bm, edges_separate);
+ bmesh_kernel_vert_separate__cleanup(bm, edges_separate);
}
}
@@ -2472,7 +2478,7 @@ void BM_vert_separate_hflag(
LinkNode *edges_orig = NULL;
do {
BMLoop *l_sep = e->l;
- bmesh_edge_separate(bm, e, l_sep, copy_select);
+ bmesh_kernel_edge_separate(bm, e, l_sep, copy_select);
/* trick to avoid looping over separated edges */
if (edges_separate == NULL && edges_orig == NULL) {
e_first = l_sep->e;
@@ -2486,10 +2492,10 @@ void BM_vert_separate_hflag(
}
} while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
- bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
+ bmesh_kernel_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
if (edges_separate) {
- bmesh_vert_separate__cleanup(bm, edges_separate);
+ bmesh_kernel_vert_separate__cleanup(bm, edges_separate);
}
}
@@ -2574,7 +2580,7 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
* \note Does nothing if \a l_sep is already the only loop in the
* edge radial.
*/
-void bmesh_edge_separate(
+void bmesh_kernel_edge_separate(
BMesh *bm, BMEdge *e, BMLoop *l_sep,
const bool copy_select)
{
@@ -2620,7 +2626,7 @@ void bmesh_edge_separate(
*
* \note Will be a no-op and return original vertex if only two edges at that vertex.
*/
-BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep)
+BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
{
BMVert *v_new = NULL;
BMVert *v_sep = l_sep->v;
@@ -2630,10 +2636,12 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep)
/* peel the face from the edge radials on both sides of the
* loop vert, disconnecting the face from its fan */
- if (!BM_edge_is_boundary(l_sep->e))
- bmesh_edge_separate(bm, l_sep->e, l_sep, false);
- if (!BM_edge_is_boundary(l_sep->prev->e))
- bmesh_edge_separate(bm, l_sep->prev->e, l_sep->prev, false);
+ if (!BM_edge_is_boundary(l_sep->e)) {
+ bmesh_kernel_edge_separate(bm, l_sep->e, l_sep, false);
+ }
+ if (!BM_edge_is_boundary(l_sep->prev->e)) {
+ bmesh_kernel_edge_separate(bm, l_sep->prev->e, l_sep->prev, false);
+ }
/* do inline, below */
#if 0
@@ -2681,21 +2689,23 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep)
}
/**
- * A version of #bmesh_urmv_loop that disconnects multiple loops at once.
+ * A version of #bmesh_kernel_unglue_region_make_vert that disconnects multiple loops at once.
* The loops must all share the same vertex, can be in any order
* and are all moved to use a single new vertex - which is returned.
*
* This function handles the details of finding fans boundaries.
*/
-BMVert *bmesh_urmv_loop_multi(
+BMVert *bmesh_kernel_unglue_region_make_vert_multi(
BMesh *bm, BMLoop **larr, int larr_len)
{
BMVert *v_sep = larr[0]->v;
BMVert *v_new;
+ int edges_len = 0;
int i;
- bool is_mixed_any = false;
-
- BLI_SMALLSTACK_DECLARE(edges, BMEdge *);
+ /* any edges not owned by 'larr' loops connected to 'v_sep'? */
+ bool is_mixed_edge_any = false;
+ /* any loops not owned by 'larr' radially connected to 'larr' loop edges? */
+ bool is_mixed_loop_any = false;
#define LOOP_VISIT _FLAG_WALK
#define EDGE_VISIT _FLAG_WALK
@@ -2713,58 +2723,74 @@ BMVert *bmesh_urmv_loop_multi(
* while doing a radial loop (where loops may be adjacent) */
BM_ELEM_API_FLAG_ENABLE(l_sep->next, LOOP_VISIT);
BM_ELEM_API_FLAG_ENABLE(l_sep->prev, LOOP_VISIT);
- }
-
- for (i = 0; i < larr_len; i++) {
- BMLoop *l_sep = larr[i];
BMLoop *loop_pair[2] = {l_sep, l_sep->prev};
- int j;
- for (j = 0; j < ARRAY_SIZE(loop_pair); j++) {
+ for (int j = 0; j < ARRAY_SIZE(loop_pair); j++) {
BMEdge *e = loop_pair[j]->e;
if (!BM_ELEM_API_FLAG_TEST(e, EDGE_VISIT)) {
- BMLoop *l_iter, *l_first;
- bool is_mixed = false;
-
BM_ELEM_API_FLAG_ENABLE(e, EDGE_VISIT);
+ edges_len += 1;
+ }
+ }
+ }
- l_iter = l_first = e->l;
+ BMEdge **edges = BLI_array_alloca(edges, edges_len);
+ STACK_DECLARE(edges);
+
+ STACK_INIT(edges, edges_len);
+
+ {
+ BMEdge *e_first, *e_iter;
+ e_iter = e_first = v_sep->e;
+ do {
+ if (BM_ELEM_API_FLAG_TEST(e_iter, EDGE_VISIT)) {
+ BMLoop *l_iter, *l_first;
+ bool is_mixed_loop = false;
+
+ l_iter = l_first = e_iter->l;
do {
if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
- is_mixed = true;
- is_mixed_any = true;
+ is_mixed_loop = true;
break;
}
} while ((l_iter = l_iter->radial_next) != l_first);
- if (is_mixed) {
+ if (is_mixed_loop) {
/* ensure the first loop is one we don't own so we can do a quick check below
* on the edge's loop-flag to see if the edge is mixed or not. */
- e->l = l_iter;
+ e_iter->l = l_iter;
+
+ is_mixed_loop_any = true;
}
- BLI_SMALLSTACK_PUSH(edges, e);
+
+ STACK_PUSH(edges, e_iter);
}
- }
+ else {
+ /* at least one edge attached isn't connected to our loops */
+ is_mixed_edge_any = true;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v_sep)) != e_first);
}
- if (is_mixed_any == false) {
+ BLI_assert(edges_len == STACK_SIZE(edges));
+
+ if (is_mixed_loop_any == false && is_mixed_edge_any == false) {
/* all loops in 'larr' are the sole owners of their edges.
* nothing to split away from, this is a no-op */
v_new = v_sep;
}
else {
- BMEdge *e;
-
- BLI_assert(!BLI_SMALLSTACK_IS_EMPTY(edges));
-
v_new = BM_vert_create(bm, v_sep->co, v_sep, BM_CREATE_NOP);
- while ((e = BLI_SMALLSTACK_POP(edges))) {
+
+ for (i = 0; i < STACK_SIZE(edges); i++) {
+ BMEdge *e = edges[i];
BMLoop *l_iter, *l_first, *l_next;
BMEdge *e_new;
/* disable so copied edge isn't left dirty (loop edges are cleared last too) */
BM_ELEM_API_FLAG_DISABLE(e, EDGE_VISIT);
+ /* will always be false when (is_mixed_loop_any == false) */
if (!BM_ELEM_API_FLAG_TEST(e->l, LOOP_VISIT)) {
/* edge has some loops owned by us, some owned by other loops */
BMVert *e_new_v_pair[2];
@@ -2853,9 +2879,9 @@ static void bmesh_edge_vert_swap__recursive(BMEdge *e, BMVert *v_dst, BMVert *v_
/**
* This function assumes l_sep is apart of a larger fan which has already been
- * isolated by calling bmesh_edge_separate to segregate it radially.
+ * isolated by calling #bmesh_kernel_edge_separate to segregate it radially.
*/
-BMVert *bmesh_urmv_loop_region(BMesh *bm, BMLoop *l_sep)
+BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep)
{
BMVert *v_new = BM_vert_create(bm, l_sep->v->co, l_sep->v, BM_CREATE_NOP);
/* passing either 'l_sep->e', 'l_sep->prev->e' will work */
@@ -2864,20 +2890,6 @@ BMVert *bmesh_urmv_loop_region(BMesh *bm, BMLoop *l_sep)
return v_new;
}
-
-/**
- * \brief Unglue Region Make Vert (URMV)
- *
- * Disconnects f_sep from the vertex fan at \a v_sep
- *
- * \return The newly created BMVert
- */
-BMVert *bmesh_urmv(BMesh *bm, BMFace *f_sep, BMVert *v_sep)
-{
- BMLoop *l = BM_face_vert_share_loop(f_sep, v_sep);
- return bmesh_urmv_loop(bm, l);
-}
-
/**
* Avoid calling this where possible,
* low level function so both face pointers remain intact but point to swapped data.
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index f72e9d7b198..fb6b66809f3 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -64,21 +64,16 @@ void BM_face_kill(BMesh *bm, BMFace *f);
void BM_edge_kill(BMesh *bm, BMEdge *e);
void BM_vert_kill(BMesh *bm, BMVert *v);
-void bmesh_edge_separate(
- BMesh *bm, BMEdge *e, BMLoop *l_sep,
- const bool copy_select);
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src);
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src);
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b);
-void bmesh_vert_separate(
- BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
- const bool copy_select);
-
-void bmesh_loop_reverse(
+void bmesh_kernel_loop_reverse(
BMesh *bm, BMFace *f,
const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip);
+void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b);
+
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del);
void BM_vert_separate(
BMesh *bm, BMVert *v, BMEdge **e_in, int e_in_len, const bool copy_select,
@@ -90,34 +85,43 @@ void BM_vert_separate_wire_hflag(
BMesh *bm, BMVert *v_dst, BMVert *v_src,
const char hflag);
-/* EULER API - For modifying structure */
-BMFace *bmesh_sfme(
+/**
+ * BMesh Kernel: For modifying structure.
+ *
+ * Names are on the verbose side but these are only for low-level access.
+ */
+void bmesh_kernel_vert_separate(
+ BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
+ const bool copy_select);
+void bmesh_kernel_edge_separate(
+ BMesh *bm, BMEdge *e, BMLoop *l_sep,
+ const bool copy_select);
+
+BMFace *bmesh_kernel_split_face_make_edge(
BMesh *bm, BMFace *f,
BMLoop *l1, BMLoop *l2,
BMLoop **r_l,
#ifdef USE_BMESH_HOLES
- ListBase *holes,
+ ListBase *holes,
#endif
- BMEdge *example,
- const bool no_double
- );
+ BMEdge *example,
+ const bool no_double
+ );
-BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
-BMEdge *bmesh_jekv(
+BMVert *bmesh_kernel_split_edge_make_vert(
+ BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
+BMEdge *bmesh_kernel_join_edge_kill_vert(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
const bool do_del, const bool check_edge_splice,
const bool kill_degenerate_faces);
-BMVert *bmesh_jvke(
+BMVert *bmesh_kernel_join_vert_kill_edge(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
const bool do_del, const bool check_edge_double,
const bool kill_degenerate_faces);
-BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
-BMVert *bmesh_urmv(BMesh *bm, BMFace *f_sep, BMVert *v_sep);
-BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep);
-BMVert *bmesh_urmv_loop_multi(
- BMesh *bm, BMLoop **larr, int larr_len);
-BMVert *bmesh_urmv_loop_region(BMesh *bm, BMLoop *l_sep);
+BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
-void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b);
+BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep);
+BMVert *bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len);
+BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep);
#endif /* __BMESH_CORE_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index 5e1d9c3a98d..b3b23933d2f 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -32,6 +32,7 @@
#include "BLI_math_vector.h"
#include "BLI_listbase.h"
#include "BLI_mempool.h"
+#include "BLI_utildefines_iter.h"
#include "bmesh.h"
@@ -58,7 +59,7 @@ static int bm_vert_other_tag(
{
BMIter iter;
BMEdge *e, *e_next = NULL;
- unsigned int count = 0;
+ uint count = 0;
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
if (BM_elem_flag_test(e, BM_ELEM_INTERNAL_TAG)) {
@@ -708,21 +709,16 @@ void BM_edgeloop_expand(
}
if (el_store->len < el_store_len) {
- const int step = max_ii(1, el_store->len / (el_store->len % el_store_len));
- LinkData *node_first = el_store->verts.first;
- LinkData *node_curr = node_first;
+ LinkData *node_curr = el_store->verts.first;
- do {
- LinkData *node_curr_init = node_curr;
- LinkData *node_curr_copy;
- int i = 0;
- BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (&el_store->verts, node_curr, node_curr_init) {
- if (i++ < step) {
- break;
- }
+ int iter_prev = 0;
+ BLI_FOREACH_SPARSE_RANGE(el_store->len, (el_store_len - el_store->len), iter) {
+ while (iter_prev < iter) {
+ node_curr = node_curr->next;
+ iter_prev += 1;
}
- BLI_LISTBASE_CIRCULAR_FORWARD_END (&el_store->verts, node_curr, node_curr_init);
+ LinkData *node_curr_copy;
node_curr_copy = MEM_dupallocN(node_curr);
if (split == false) {
BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
@@ -730,7 +726,8 @@ void BM_edgeloop_expand(
}
else {
if (node_curr->next || (el_store->flag & BM_EDGELOOP_IS_CLOSED)) {
- EDGE_SPLIT(node_curr_copy, node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first);
+ EDGE_SPLIT(node_curr_copy,
+ node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first);
BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
node_curr = node_curr_copy->next;
}
@@ -742,9 +739,11 @@ void BM_edgeloop_expand(
split_swap = !split_swap;
}
el_store->len++;
- } while (el_store->len < el_store_len);
+ iter_prev += 1;
+ }
}
+#undef BKE_FOREACH_SUBSET_OF_RANGE
#undef EDGE_SPLIT
BLI_assert(el_store->len == el_store_len);
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index f51013c3f1c..20ee31251e8 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -339,7 +339,7 @@ static bool mdisp_in_mdispquad(
compute_mdisp_quad(l_dst, l_dst_f_center, v1, v2, v3, v4, e1, e2);
/* expand quad a bit */
- cent_quad_v3(c, v1, v2, v3, v4);
+ mid_v3_v3v3v3v3(c, v1, v2, v3, v4);
sub_v3_v3(v1, c); sub_v3_v3(v2, c);
sub_v3_v3(v3, c); sub_v3_v3(v4, c);
diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h
index 0551d824131..ab066682081 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.h
+++ b/source/blender/bmesh/intern/bmesh_iterators.h
@@ -211,12 +211,12 @@ void *BMO_iter_as_arrayN(
int BM_iter_mesh_bitmap_from_filter(
const char itype, BMesh *bm,
- unsigned int *bitmap,
+ uint *bitmap,
bool (*test_fn)(BMElem *, void *user_data),
void *user_data);
int BM_iter_mesh_bitmap_from_filter_tessface(
BMesh *bm,
- unsigned int *bitmap,
+ uint *bitmap,
bool (*test_fn)(BMFace *, void *user_data),
void *user_data);
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index 2591c33fc73..1d16dbc1836 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -88,7 +88,7 @@ struct BMLog {
/* Mapping from unique IDs to vertices and faces
*
- * Each vertex and face in the log gets a unique unsigned integer
+ * Each vertex and face in the log gets a unique uinteger
* assigned. That ID is taken from the set managed by the
* unused_ids range tree.
*
@@ -120,7 +120,7 @@ typedef struct {
} BMLogVert;
typedef struct {
- unsigned int v_ids[3];
+ uint v_ids[3];
char hflag;
} BMLogFace;
@@ -131,14 +131,14 @@ typedef struct {
#define logkey_cmp BLI_ghashutil_intcmp
/* Get the vertex's unique ID from the log */
-static unsigned int bm_log_vert_id_get(BMLog *log, BMVert *v)
+static uint bm_log_vert_id_get(BMLog *log, BMVert *v)
{
BLI_assert(BLI_ghash_haskey(log->elem_to_id, v));
return GET_UINT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, v));
}
/* Set the vertex's unique ID in the log */
-static void bm_log_vert_id_set(BMLog *log, BMVert *v, unsigned int id)
+static void bm_log_vert_id_set(BMLog *log, BMVert *v, uint id)
{
void *vid = SET_UINT_IN_POINTER(id);
@@ -147,7 +147,7 @@ static void bm_log_vert_id_set(BMLog *log, BMVert *v, unsigned int id)
}
/* Get a vertex from its unique ID */
-static BMVert *bm_log_vert_from_id(BMLog *log, unsigned int id)
+static BMVert *bm_log_vert_from_id(BMLog *log, uint id)
{
void *key = SET_UINT_IN_POINTER(id);
BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
@@ -155,14 +155,14 @@ static BMVert *bm_log_vert_from_id(BMLog *log, unsigned int id)
}
/* Get the face's unique ID from the log */
-static unsigned int bm_log_face_id_get(BMLog *log, BMFace *f)
+static uint bm_log_face_id_get(BMLog *log, BMFace *f)
{
BLI_assert(BLI_ghash_haskey(log->elem_to_id, f));
return GET_UINT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, f));
}
/* Set the face's unique ID in the log */
-static void bm_log_face_id_set(BMLog *log, BMFace *f, unsigned int id)
+static void bm_log_face_id_set(BMLog *log, BMFace *f, uint id)
{
void *fid = SET_UINT_IN_POINTER(id);
@@ -171,7 +171,7 @@ static void bm_log_face_id_set(BMLog *log, BMFace *f, unsigned int id)
}
/* Get a face from its unique ID */
-static BMFace *bm_log_face_from_id(BMLog *log, unsigned int id)
+static BMFace *bm_log_face_from_id(BMLog *log, uint id)
{
void *key = SET_UINT_IN_POINTER(id);
BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
@@ -255,7 +255,7 @@ static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts)
GHASH_ITER (gh_iter, verts) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
BMVert *v = bm_log_vert_from_id(log, id);
/* Ensure the log has the final values of the vertex before
@@ -271,7 +271,7 @@ static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces)
GHashIterator gh_iter;
GHASH_ITER (gh_iter, faces) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
BMFace *f = bm_log_face_from_id(log, id);
BMEdge *e_tri[3];
BMLoop *l_iter;
@@ -333,7 +333,7 @@ static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts)
GHASH_ITER (gh_iter, verts) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
BMVert *v = bm_log_vert_from_id(log, id);
float mask;
short normal[3];
@@ -355,7 +355,7 @@ static void bm_log_face_values_swap(BMLog *log, GHash *faces)
GHASH_ITER (gh_iter, faces) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
BMFace *f = bm_log_face_from_id(log, id);
SWAP(char, f->head.hflag, lf->hflag);
@@ -374,13 +374,13 @@ static void bm_log_assign_ids(BMesh *bm, BMLog *log)
/* Generate vertex IDs */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- unsigned int id = range_tree_uint_take_any(log->unused_ids);
+ uint id = range_tree_uint_take_any(log->unused_ids);
bm_log_vert_id_set(log, v, id);
}
/* Generate face IDs */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- unsigned int id = range_tree_uint_take_any(log->unused_ids);
+ uint id = range_tree_uint_take_any(log->unused_ids);
bm_log_face_id_set(log, f, id);
}
}
@@ -425,7 +425,7 @@ static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash)
GHASH_ITER (gh_iter, id_ghash) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
range_tree_uint_retake(unused_ids, id);
}
@@ -433,8 +433,8 @@ static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash)
static int uint_compare(const void *a_v, const void *b_v)
{
- const unsigned int *a = a_v;
- const unsigned int *b = b_v;
+ const uint *a = a_v;
+ const uint *b = b_v;
return (*a) < (*b);
}
@@ -446,10 +446,10 @@ static int uint_compare(const void *a_v, const void *b_v)
* 10 -> 3
* 3 -> 1
*/
-static GHash *bm_log_compress_ids_to_indices(unsigned int *ids, unsigned int totid)
+static GHash *bm_log_compress_ids_to_indices(uint *ids, uint totid)
{
GHash *map = BLI_ghash_int_new_ex(__func__, totid);
- unsigned int i;
+ uint i;
qsort(ids, totid, sizeof(*ids), uint_compare);
@@ -469,7 +469,7 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
GHASH_ITER (gh_iter, id_ghash) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
range_tree_uint_release(log->unused_ids, id);
}
}
@@ -480,7 +480,7 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
BMLog *BM_log_create(BMesh *bm)
{
BMLog *log = MEM_callocN(sizeof(*log), __func__);
- const unsigned int reserve_num = (unsigned int)(bm->totvert + bm->totface);
+ const uint reserve_num = (uint)(bm->totvert + bm->totface);
log->unused_ids = range_tree_uint_alloc(0, (unsigned)-1);
log->id_to_elem = BLI_ghash_new_ex(logkey_hash, logkey_cmp, __func__, reserve_num);
@@ -593,8 +593,8 @@ int BM_log_length(const BMLog *log)
/* Apply a consistent ordering to BMesh vertices */
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
{
- unsigned int *varr;
- unsigned int *farr;
+ uint *varr;
+ uint *farr;
GHash *id_to_idx;
@@ -602,7 +602,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
BMVert *v;
BMFace *f;
- unsigned int i;
+ uint i;
/* Put all vertex IDs into an array */
varr = MEM_mallocN(sizeof(int) * (size_t)bm->totvert, __func__);
@@ -617,7 +617,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
}
/* Create BMVert index remap array */
- id_to_idx = bm_log_compress_ids_to_indices(varr, (unsigned int)bm->totvert);
+ id_to_idx = bm_log_compress_ids_to_indices(varr, (uint)bm->totvert);
BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
const unsigned id = bm_log_vert_id_get(log, v);
const void *key = SET_UINT_IN_POINTER(id);
@@ -627,7 +627,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
BLI_ghash_free(id_to_idx, NULL, NULL);
/* Create BMFace index remap array */
- id_to_idx = bm_log_compress_ids_to_indices(farr, (unsigned int)bm->totface);
+ id_to_idx = bm_log_compress_ids_to_indices(farr, (uint)bm->totface);
BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
const unsigned id = bm_log_face_id_get(log, f);
const void *key = SET_UINT_IN_POINTER(id);
@@ -835,7 +835,7 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
{
BMLogEntry *entry = log->current_entry;
BMLogVert *lv;
- unsigned int v_id = bm_log_vert_id_get(log, v);
+ uint v_id = bm_log_vert_id_get(log, v);
void *key = SET_UINT_IN_POINTER(v_id);
void **val_p;
@@ -859,7 +859,7 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogVert *lv;
- unsigned int v_id = range_tree_uint_take_any(log->unused_ids);
+ uint v_id = range_tree_uint_take_any(log->unused_ids);
void *key = SET_UINT_IN_POINTER(v_id);
bm_log_vert_id_set(log, v, v_id);
@@ -876,7 +876,7 @@ void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
void BM_log_face_modified(BMLog *log, BMFace *f)
{
BMLogFace *lf;
- unsigned int f_id = bm_log_face_id_get(log, f);
+ uint f_id = bm_log_face_id_get(log, f);
void *key = SET_UINT_IN_POINTER(f_id);
lf = bm_log_face_alloc(log, f);
@@ -892,7 +892,7 @@ void BM_log_face_modified(BMLog *log, BMFace *f)
void BM_log_face_added(BMLog *log, BMFace *f)
{
BMLogFace *lf;
- unsigned int f_id = range_tree_uint_take_any(log->unused_ids);
+ uint f_id = range_tree_uint_take_any(log->unused_ids);
void *key = SET_UINT_IN_POINTER(f_id);
/* Only triangles are supported for now */
@@ -922,7 +922,7 @@ void BM_log_face_added(BMLog *log, BMFace *f)
void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogEntry *entry = log->current_entry;
- unsigned int v_id = bm_log_vert_id_get(log, v);
+ uint v_id = bm_log_vert_id_get(log, v);
void *key = SET_UINT_IN_POINTER(v_id);
/* if it has a key, it shouldn't be NULL */
@@ -963,7 +963,7 @@ void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
void BM_log_face_removed(BMLog *log, BMFace *f)
{
BMLogEntry *entry = log->current_entry;
- unsigned int f_id = bm_log_face_id_get(log, f);
+ uint f_id = bm_log_face_id_get(log, f);
void *key = SET_UINT_IN_POINTER(f_id);
/* if it has a key, it shouldn't be NULL */
@@ -991,11 +991,11 @@ void BM_log_all_added(BMesh *bm, BMLog *log)
/* avoid unnecessary resizing on initialization */
if (BLI_ghash_size(log->current_entry->added_verts) == 0) {
- BLI_ghash_reserve(log->current_entry->added_verts, (unsigned int)bm->totvert);
+ BLI_ghash_reserve(log->current_entry->added_verts, (uint)bm->totvert);
}
if (BLI_ghash_size(log->current_entry->added_faces) == 0) {
- BLI_ghash_reserve(log->current_entry->added_faces, (unsigned int)bm->totface);
+ BLI_ghash_reserve(log->current_entry->added_faces, (uint)bm->totface);
}
/* Log all vertices as newly created */
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 7178a8132d2..7f2032d5f53 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -70,7 +70,7 @@ static void recount_totsels(BMesh *bm)
}
}
-/** \name BMesh helper functions for selection flushing.
+/** \name BMesh helper functions for selection & hide flushing.
* \{ */
static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
@@ -102,6 +102,20 @@ static bool bm_vert_is_edge_select_any(const BMVert *v)
}
#endif
+static bool bm_vert_is_edge_visible_any(const BMVert *v)
+{
+ if (v->e) {
+ const BMEdge *e_iter, *e_first;
+ e_iter = e_first = v->e;
+ do {
+ if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) {
+ return true;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+ return false;
+}
+
static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
{
const BMLoop *l_iter = l_first;
@@ -131,6 +145,20 @@ static bool bm_edge_is_face_select_any(const BMEdge *e)
}
#endif
+static bool bm_edge_is_face_visible_any(const BMEdge *e)
+{
+ if (e->l) {
+ const BMLoop *l_iter, *l_first;
+ l_iter = l_first = e->l;
+ do {
+ if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
+ return true;
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ return false;
+}
+
/** \} */
/**
@@ -1198,87 +1226,111 @@ void BM_mesh_elem_hflag_enable_all(
/***************** Mesh Hiding stuff *********** */
+/**
+ * Hide unless any connected elements are visible.
+ * Run this after hiding a connected edge or face.
+ */
static void vert_flush_hide_set(BMVert *v)
{
- BMIter iter;
- BMEdge *e;
- bool hide = true;
-
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- hide = hide && BM_elem_flag_test(e, BM_ELEM_HIDDEN);
- }
-
- BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
+ BM_elem_flag_set(v, BM_ELEM_HIDDEN, !bm_vert_is_edge_visible_any(v));
}
-static void edge_flush_hide(BMEdge *e)
+/**
+ * Hide unless any connected elements are visible.
+ * Run this after hiding a connected face.
+ */
+static void edge_flush_hide_set(BMEdge *e)
{
- BMIter iter;
- BMFace *f;
- bool hide = true;
-
- BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
- hide = hide && BM_elem_flag_test(f, BM_ELEM_HIDDEN);
- }
-
- BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
+ BM_elem_flag_set(e, BM_ELEM_HIDDEN, !bm_edge_is_face_visible_any(e));
}
void BM_vert_hide_set(BMVert *v, const bool hide)
{
/* vert hiding: vert + surrounding edges and faces */
- BMIter iter, fiter;
- BMEdge *e;
- BMFace *f;
-
BLI_assert(v->head.htype == BM_VERT);
+ if (hide) {
+ BLI_assert(!BM_elem_flag_test(v, BM_ELEM_SELECT));
+ }
BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
-
- BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
- }
+ if (v->e) {
+ BMEdge *e_iter, *e_first;
+ e_iter = e_first = v->e;
+ do {
+ BM_elem_flag_set(e_iter, BM_ELEM_HIDDEN, hide);
+ if (e_iter->l) {
+ const BMLoop *l_radial_iter, *l_radial_first;
+ l_radial_iter = l_radial_first = e_iter->l;
+ do {
+ BM_elem_flag_set(l_radial_iter->f, BM_ELEM_HIDDEN, hide);
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
}
}
void BM_edge_hide_set(BMEdge *e, const bool hide)
{
- BMIter iter;
- BMFace *f;
- /* BMVert *v; */
-
BLI_assert(e->head.htype == BM_EDGE);
+ if (hide) {
+ BLI_assert(!BM_elem_flag_test(e, BM_ELEM_SELECT));
+ }
/* edge hiding: faces around the edge */
- BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
- BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
+ if (e->l) {
+ const BMLoop *l_iter, *l_first;
+ l_iter = l_first = e->l;
+ do {
+ BM_elem_flag_set(l_iter->f, BM_ELEM_HIDDEN, hide);
+ } while ((l_iter = l_iter->radial_next) != l_first);
}
BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
/* hide vertices if necessary */
- vert_flush_hide_set(e->v1);
- vert_flush_hide_set(e->v2);
+ if (hide) {
+ vert_flush_hide_set(e->v1);
+ vert_flush_hide_set(e->v2);
+ }
+ else {
+ BM_elem_flag_disable(e->v1, BM_ELEM_HIDDEN);
+ BM_elem_flag_disable(e->v2, BM_ELEM_HIDDEN);
+ }
}
void BM_face_hide_set(BMFace *f, const bool hide)
{
- BMIter iter;
- BMLoop *l;
-
BLI_assert(f->head.htype == BM_FACE);
+ if (hide) {
+ BLI_assert(!BM_elem_flag_test(f, BM_ELEM_SELECT));
+ }
BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
- BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
- edge_flush_hide(l->e);
+ if (hide) {
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter;
+
+ l_iter = l_first;
+ do {
+ edge_flush_hide_set(l_iter->e);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ l_iter = l_first;
+ do {
+ vert_flush_hide_set(l_iter->v);
+ } while ((l_iter = l_iter->next) != l_first);
}
+ else {
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter;
- BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
- vert_flush_hide_set(l->v);
+ l_iter = l_first;
+ do {
+ BM_elem_flag_disable(l_iter->e, BM_ELEM_HIDDEN);
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_HIDDEN);
+ } while ((l_iter = l_iter->next) != l_first);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 57a6d8d2e1a..2ff670c770e 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -486,8 +486,7 @@ static void bm_mesh_edges_sharp_tag(
BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float split_angle,
float (*r_lnos)[3])
{
- BMIter eiter, viter;
- BMVert *v;
+ BMIter eiter;
BMEdge *e;
int i;
@@ -498,19 +497,13 @@ static void bm_mesh_edges_sharp_tag(
}
{
- char htype = BM_LOOP;
+ char htype = BM_VERT | BM_LOOP;
if (fnos) {
htype |= BM_FACE;
}
BM_mesh_elem_index_ensure(bm, htype);
}
- /* Clear all vertices' tags (means they are all smooth for now). */
- BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
- BM_elem_index_set(v, i); /* set_inline */
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- }
-
/* This first loop checks which edges are actually smooth, and pre-populate lnos with vnos (as if they were
* all smooth).
*/
@@ -551,20 +544,45 @@ static void bm_mesh_edges_sharp_tag(
no = vnos ? vnos[BM_elem_index_get(l_b->v)] : l_b->v->no;
copy_v3_v3(r_lnos[BM_elem_index_get(l_b)], no);
}
- else {
- /* Sharp edge, tag its verts as such. */
- BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
+ }
+ }
+
+ bm->elem_index_dirty &= ~BM_EDGE;
+}
+
+/* Check whether gievn loop is part of an unknown-so-far cyclic smooth fan, or not.
+ * Needed because cyclic smooth fans have no obvious 'entry point', and yet we need to walk them once, and only once. */
+static bool bm_mesh_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
+{
+ BMLoop *lfan_pivot_next = l_curr;
+ BMEdge *e_next = l_curr->e;
+
+ BLI_assert(!BM_elem_flag_test(lfan_pivot_next, BM_ELEM_TAG));
+ BM_elem_flag_enable(lfan_pivot_next, BM_ELEM_TAG);
+
+ while (true) {
+ /* Much simpler than in sibling code with basic Mesh data! */
+ lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot_next, &e_next);
+
+ if (!lfan_pivot_next || !BM_elem_flag_test(e_next, BM_ELEM_TAG)) {
+ /* Sharp loop/edge, so not a cyclic smooth fan... */
+ return false;
+ }
+ /* Smooth loop/edge... */
+ else if (BM_elem_flag_test(lfan_pivot_next, BM_ELEM_TAG)) {
+ if (lfan_pivot_next == l_curr) {
+ /* We walked around a whole cyclic smooth fan without finding any already-processed loop, means we can
+ * use initial l_curr/l_prev edge as start for this smooth fan. */
+ return true;
}
+ /* ... already checked in some previous looping, we can abort. */
+ return false;
}
else {
- /* Sharp edge, tag its verts as such. */
- BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
+ /* ... we can skip it in future, and keep checking the smooth fan. */
+ BM_elem_flag_enable(lfan_pivot_next, BM_ELEM_TAG);
}
}
-
- bm->elem_index_dirty &= ~(BM_EDGE | BM_VERT);
}
/* BMesh version of BKE_mesh_normals_loop_split() in mesh_evaluate.c
@@ -587,13 +605,11 @@ static void bm_mesh_loops_calc_normals(
BLI_Stack *edge_vectors = NULL;
{
- char htype = BM_LOOP;
+ char htype = 0;
if (vcos) {
htype |= BM_VERT;
}
- if (fnos) {
- htype |= BM_FACE;
- }
+ /* Face/Loop indices are set inline below. */
BM_mesh_elem_index_ensure(bm, htype);
}
@@ -606,6 +622,21 @@ static void bm_mesh_loops_calc_normals(
edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
}
+ /* Clear all loops' tags (means none are to be skipped for now). */
+ int index_face, index_loop = 0;
+ BM_ITER_MESH_INDEX (f_curr, &fiter, bm, BM_FACES_OF_MESH, index_face) {
+ BMLoop *l_curr, *l_first;
+
+ BM_elem_index_set(f_curr, index_face); /* set_inline */
+
+ l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
+ do {
+ BM_elem_index_set(l_curr, index_loop++); /* set_inline */
+ BM_elem_flag_disable(l_curr, BM_ELEM_TAG);
+ } while ((l_curr = l_curr->next) != l_first);
+ }
+ bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
+
/* We now know edges that can be smoothed (they are tagged), and edges that will be hard (they aren't).
* Now, time to generate the normals.
*/
@@ -614,16 +645,16 @@ static void bm_mesh_loops_calc_normals(
l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
do {
+ /* A smooth edge, we have to check for cyclic smooth fan case.
+ * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as
+ * 'entry point', otherwise we can skip it. */
+ /* Note: In theory, we could make bm_mesh_loop_check_cyclic_smooth_fan() store mlfan_pivot's in a stack,
+ * to avoid having to fan again around the vert during actual computation of clnor & clnorspace.
+ * However, this would complicate the code, add more memory usage, and BM_vert_step_fan_loop()
+ * is quite cheap in term of CPU cycles, so really think it's not worth it. */
if (BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
- (!r_lnors_spacearr || BM_elem_flag_test(l_curr->v, BM_ELEM_TAG)))
+ (BM_elem_flag_test(l_curr, BM_ELEM_TAG) || !bm_mesh_loop_check_cyclic_smooth_fan(l_curr)))
{
- /* A smooth edge, and we are not generating lnors_spacearr, or the related vertex is sharp.
- * We skip it because it is either:
- * - in the middle of a 'smooth fan' already computed (or that will be as soon as we hit
- * one of its ends, i.e. one of its two sharp edges), or...
- * - the related vertex is a "full smooth" one, in which case pre-populated normals from vertex
- * are just fine!
- */
}
else if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
!BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG))
@@ -744,7 +775,7 @@ static void bm_mesh_loops_calc_normals(
}
{
- /* Code similar to accumulate_vertex_normals_poly. */
+ /* Code similar to accumulate_vertex_normals_poly_v3. */
/* Calculate angle between the two poly edges incident on this vertex. */
const BMFace *f = lfan_pivot->f;
const float fac = saacos(dot_v3v3(vec_next, vec_curr));
@@ -1481,23 +1512,6 @@ int BM_mesh_elem_count(BMesh *bm, const char htype)
}
}
-/**
- * Special case: Python uses custom-data layers to hold PyObject references.
- * These have to be kept in-place, else the PyObject's we point to, wont point back to us.
- *
- * \note ``ele_src`` Is a duplicate, so we don't need to worry about getting in a feedback loop.
- *
- * \note If there are other customdata layers which need this functionality, it should be generalized.
- * However #BM_mesh_remap is currently the only place where this is done.
- */
-static void bm_mesh_remap_cd_update(
- BMHeader *ele_dst, BMHeader *ele_src,
- const int cd_elem_pyptr)
-{
- void **pyptr_dst_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_dst), cd_elem_pyptr);
- void **pyptr_src_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_src), cd_elem_pyptr);
- *pyptr_dst_p = *pyptr_src_p;
-}
/**
* Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
@@ -1513,9 +1527,9 @@ static void bm_mesh_remap_cd_update(
*/
void BM_mesh_remap(
BMesh *bm,
- const unsigned int *vert_idx,
- const unsigned int *edge_idx,
- const unsigned int *face_idx)
+ const uint *vert_idx,
+ const uint *edge_idx,
+ const uint *face_idx)
{
/* Mapping old to new pointers. */
GHash *vptr_map = NULL, *eptr_map = NULL, *fptr_map = NULL;
@@ -1538,7 +1552,9 @@ void BM_mesh_remap(
if (vert_idx) {
BMVert **verts_pool, *verts_copy, **vep;
int i, totvert = bm->totvert;
- const unsigned int *new_idx;
+ const uint *new_idx;
+ /* Special case: Python uses custom - data layers to hold PyObject references.
+ * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
const int cd_vert_pyptr = CustomData_get_offset(&bm->vdata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
@@ -1547,9 +1563,14 @@ void BM_mesh_remap(
/* Make a copy of all vertices. */
verts_pool = bm->vtable;
verts_copy = MEM_mallocN(sizeof(BMVert) * totvert, "BM_mesh_remap verts copy");
+ void **pyptrs = (cd_vert_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totvert, __func__) : NULL;
for (i = totvert, ve = verts_copy + totvert - 1, vep = verts_pool + totvert - 1; i--; ve--, vep--) {
*ve = **vep;
/* printf("*vep: %p, verts_pool[%d]: %p\n", *vep, i, verts_pool[i]);*/
+ if (cd_vert_pyptr != -1) {
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)ve), cd_vert_pyptr);
+ pyptrs[i] = *pyptr;
+ }
}
/* Copy back verts to their new place, and update old2new pointers mapping. */
@@ -1562,20 +1583,26 @@ void BM_mesh_remap(
/* printf("mapping vert from %d to %d (%p/%p to %p)\n", i, *new_idx, *vep, verts_pool[i], new_vep);*/
BLI_ghash_insert(vptr_map, *vep, new_vep);
if (cd_vert_pyptr != -1) {
- bm_mesh_remap_cd_update(&(*vep)->head, &new_vep->head, cd_vert_pyptr);
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_vep), cd_vert_pyptr);
+ *pyptr = pyptrs[*new_idx];
}
}
bm->elem_index_dirty |= BM_VERT;
bm->elem_table_dirty |= BM_VERT;
MEM_freeN(verts_copy);
+ if (pyptrs) {
+ MEM_freeN(pyptrs);
+ }
}
/* Remap Edges */
if (edge_idx) {
BMEdge **edges_pool, *edges_copy, **edp;
int i, totedge = bm->totedge;
- const unsigned int *new_idx;
+ const uint *new_idx;
+ /* Special case: Python uses custom - data layers to hold PyObject references.
+ * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
const int cd_edge_pyptr = CustomData_get_offset(&bm->edata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
@@ -1584,8 +1611,13 @@ void BM_mesh_remap(
/* Make a copy of all vertices. */
edges_pool = bm->etable;
edges_copy = MEM_mallocN(sizeof(BMEdge) * totedge, "BM_mesh_remap edges copy");
+ void **pyptrs = (cd_edge_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totedge, __func__) : NULL;
for (i = totedge, ed = edges_copy + totedge - 1, edp = edges_pool + totedge - 1; i--; ed--, edp--) {
*ed = **edp;
+ if (cd_edge_pyptr != -1) {
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)ed), cd_edge_pyptr);
+ pyptrs[i] = *pyptr;
+ }
}
/* Copy back verts to their new place, and update old2new pointers mapping. */
@@ -1598,20 +1630,26 @@ void BM_mesh_remap(
BLI_ghash_insert(eptr_map, *edp, new_edp);
/* printf("mapping edge from %d to %d (%p/%p to %p)\n", i, *new_idx, *edp, edges_pool[i], new_edp);*/
if (cd_edge_pyptr != -1) {
- bm_mesh_remap_cd_update(&(*edp)->head, &new_edp->head, cd_edge_pyptr);
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_edp), cd_edge_pyptr);
+ *pyptr = pyptrs[*new_idx];
}
}
bm->elem_index_dirty |= BM_EDGE;
bm->elem_table_dirty |= BM_EDGE;
MEM_freeN(edges_copy);
+ if (pyptrs) {
+ MEM_freeN(pyptrs);
+ }
}
/* Remap Faces */
if (face_idx) {
BMFace **faces_pool, *faces_copy, **fap;
int i, totface = bm->totface;
- const unsigned int *new_idx;
+ const uint *new_idx;
+ /* Special case: Python uses custom - data layers to hold PyObject references.
+ * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
const int cd_poly_pyptr = CustomData_get_offset(&bm->pdata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
@@ -1620,8 +1658,13 @@ void BM_mesh_remap(
/* Make a copy of all vertices. */
faces_pool = bm->ftable;
faces_copy = MEM_mallocN(sizeof(BMFace) * totface, "BM_mesh_remap faces copy");
+ void **pyptrs = (cd_poly_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totface, __func__) : NULL;
for (i = totface, fa = faces_copy + totface - 1, fap = faces_pool + totface - 1; i--; fa--, fap--) {
*fa = **fap;
+ if (cd_poly_pyptr != -1) {
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)fa), cd_poly_pyptr);
+ pyptrs[i] = *pyptr;
+ }
}
/* Copy back verts to their new place, and update old2new pointers mapping. */
@@ -1633,7 +1676,8 @@ void BM_mesh_remap(
*new_fap = *fa;
BLI_ghash_insert(fptr_map, *fap, new_fap);
if (cd_poly_pyptr != -1) {
- bm_mesh_remap_cd_update(&(*fap)->head, &new_fap->head, cd_poly_pyptr);
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_fap), cd_poly_pyptr);
+ *pyptr = pyptrs[*new_idx];
}
}
@@ -1641,6 +1685,9 @@ void BM_mesh_remap(
bm->elem_table_dirty |= BM_FACE;
MEM_freeN(faces_copy);
+ if (pyptrs) {
+ MEM_freeN(pyptrs);
+ }
}
/* And now, fix all vertices/edges/faces/loops pointers! */
@@ -2008,4 +2055,4 @@ void BM_mesh_toolflags_set(BMesh *bm, bool 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 6a9540c3b60..01f11f6f942 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -34,7 +34,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm);
void BM_mesh_elem_toolflags_clear(BMesh *bm);
struct BMeshCreateParams {
- unsigned int use_toolflags : 1;
+ uint use_toolflags : 1;
};
BMesh *BM_mesh_create(
@@ -88,9 +88,9 @@ int BM_mesh_elem_count(BMesh *bm, const char htype);
void BM_mesh_remap(
BMesh *bm,
- const unsigned int *vert_idx,
- const unsigned int *edge_idx,
- const unsigned int *face_idx);
+ const uint *vert_idx,
+ const uint *edge_idx,
+ const uint *face_idx);
void BM_mesh_rebuild(
BMesh *bm, const struct BMeshCreateParams *params,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index bb61f66e267..7787d704b59 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -219,6 +219,11 @@ static BMFace *bm_face_create_from_mpoly(
/**
* \brief Mesh -> BMesh
+ * \param bm: The mesh to write into, while this is typically a newly created BMesh,
+ * merging into existing data is supported.
+ * Note the custom-data layout isn't used.
+ * If more comprehensive merging is needed we should move this into a separate function
+ * since this should be kept fast for edit-mode switching and storing undo steps.
*
* \warning This function doesn't calculate face normals.
*/
@@ -226,6 +231,9 @@ void BM_mesh_bm_from_me(
BMesh *bm, Mesh *me,
const struct BMeshFromMeshParams *params)
{
+ const bool is_new =
+ !(bm->totvert ||
+ (bm->vdata.totlayer || bm->edata.totlayer || bm->pdata.totlayer || bm->ldata.totlayer));
MVert *mvert;
MEdge *medge;
MLoop *mloop;
@@ -233,19 +241,12 @@ void BM_mesh_bm_from_me(
KeyBlock *actkey, *block;
BMVert *v, **vtable = NULL;
BMEdge *e, **etable = NULL;
- BMFace *f;
+ BMFace *f, **ftable = NULL;
float (*keyco)[3] = NULL;
- int totuv, totloops, i, j;
-
- /* free custom data */
- /* this isnt needed in most cases but do just incase */
- CustomData_free(&bm->vdata, bm->totvert);
- CustomData_free(&bm->edata, bm->totedge);
- CustomData_free(&bm->ldata, bm->totloop);
- CustomData_free(&bm->pdata, bm->totface);
+ int totuv, totloops, i;
if (!me || !me->totvert) {
- if (me) { /*no verts? still copy customdata layout*/
+ if (me && is_new) { /*no verts? still copy customdata layout*/
CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_ASSIGN, 0);
CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_ASSIGN, 0);
CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_ASSIGN, 0);
@@ -259,19 +260,27 @@ void BM_mesh_bm_from_me(
return; /* sanity check */
}
- vtable = MEM_mallocN(sizeof(void **) * me->totvert, "mesh to bmesh vtable");
+ if (is_new) {
+ CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ /* make sure uv layer names are consisten */
+ totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ for (i = 0; i < totuv; i++) {
+ int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i);
+ CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name);
+ }
+ }
- /* make sure uv layer names are consisten */
- totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
- for (i = 0; i < totuv; i++) {
- int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i);
- CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name);
+ /* -------------------------------------------------------------------- */
+ /* Shape Key */
+ int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0;
+ if (is_new == false) {
+ tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY));
}
+ const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL;
if ((params->active_shapekey != 0) && (me->key != NULL)) {
actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1);
@@ -280,63 +289,68 @@ void BM_mesh_bm_from_me(
actkey = NULL;
}
- const int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0;
- const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL;
-
- if (tot_shape_keys || params->add_key_index) {
- CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+ if (is_new) {
+ if (tot_shape_keys || params->add_key_index) {
+ CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+ }
}
if (tot_shape_keys) {
- /* check if we need to generate unique ids for the shapekeys.
- * this also exists in the file reading code, but is here for
- * a sanity check */
- if (!me->key->uidgen) {
- fprintf(stderr,
- "%s had to generate shape key uid's in a situation we shouldn't need to! "
- "(bmesh internal error)\n",
- __func__);
-
- me->key->uidgen = 1;
- for (block = me->key->block.first; block; block = block->next) {
- block->uid = me->key->uidgen++;
+ if (is_new) {
+ /* check if we need to generate unique ids for the shapekeys.
+ * this also exists in the file reading code, but is here for
+ * a sanity check */
+ if (!me->key->uidgen) {
+ fprintf(stderr,
+ "%s had to generate shape key uid's in a situation we shouldn't need to! "
+ "(bmesh internal error)\n",
+ __func__);
+
+ me->key->uidgen = 1;
+ for (block = me->key->block.first; block; block = block->next) {
+ block->uid = me->key->uidgen++;
+ }
}
}
if (actkey && actkey->totelem == me->totvert) {
- keyco = actkey->data;
- bm->shapenr = params->active_shapekey;
+ keyco = params->use_shapekey ? actkey->data : NULL;
+ if (is_new) {
+ bm->shapenr = params->active_shapekey;
+ }
}
- for (i = 0, block = me->key->block.first; block; block = block->next, i++) {
- CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY,
- CD_ASSIGN, NULL, 0, block->name);
-
- j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
- bm->vdata.layers[j].uid = block->uid;
-
+ for (i = 0, block = me->key->block.first; i < tot_shape_keys; block = block->next, i++) {
+ if (is_new) {
+ CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY,
+ CD_ASSIGN, NULL, 0, block->name);
+ int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
+ bm->vdata.layers[j].uid = block->uid;
+ }
shape_key_table[i] = (const float (*)[3])block->data;
}
}
- CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
- CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
- CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
- CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
+ if (is_new) {
+ CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
+ CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
+ CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
+ CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
- BM_mesh_cd_flag_apply(bm, me->cd_flag);
+ BM_mesh_cd_flag_apply(bm, me->cd_flag);
+ }
const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
const int cd_shape_key_offset = me->key ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) : -1;
- const int cd_shape_keyindex_offset = (tot_shape_keys || params->add_key_index) ?
+ const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ?
CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1;
+ vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__);
+
for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
- v = vtable[i] = BM_vert_create(
- bm, keyco && params->use_shapekey ? keyco[i] : mvert->co, NULL,
- BM_CREATE_SKIP_CD);
+ v = vtable[i] = BM_vert_create(bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD);
BM_elem_index_set(v, i); /* set_ok */
/* transfer flag */
@@ -360,20 +374,16 @@ void BM_mesh_bm_from_me(
/* set shapekey data */
if (tot_shape_keys) {
float (*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
- for (j = 0; j < tot_shape_keys; j++, co_dst++) {
+ for (int j = 0; j < tot_shape_keys; j++, co_dst++) {
copy_v3_v3(*co_dst, shape_key_table[j][i]);
}
}
}
-
- bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */
-
- if (!me->totedge) {
- MEM_freeN(vtable);
- return;
+ if (is_new) {
+ bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */
}
- etable = MEM_mallocN(sizeof(void **) * me->totedge, "mesh to bmesh etable");
+ etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__);
medge = me->medge;
for (i = 0; i < me->totedge; i++, medge++) {
@@ -395,8 +405,14 @@ void BM_mesh_bm_from_me(
if (cd_edge_crease_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge->crease / 255.0f);
}
+ if (is_new) {
+ bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */
+ }
- bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */
+ /* only needed for selection. */
+ if (me->mselect && me->totselect != 0) {
+ ftable = MEM_mallocN(sizeof(BMFace **) * me->totpoly, __func__);
+ }
mloop = me->mloop;
mp = me->mpoly;
@@ -406,6 +422,9 @@ void BM_mesh_bm_from_me(
f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart,
bm, vtable, etable);
+ if (ftable != NULL) {
+ ftable[i] = f;
+ }
if (UNLIKELY(f == NULL)) {
printf("%s: Warning! Bad face in mesh"
@@ -428,7 +447,7 @@ void BM_mesh_bm_from_me(
f->mat_nr = mp->mat_nr;
if (i == me->act_face) bm->act_face = f;
- j = mp->loopstart;
+ int j = mp->loopstart;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
/* don't use 'j' since we may have skipped some faces, hence some loops. */
@@ -445,54 +464,49 @@ void BM_mesh_bm_from_me(
BM_face_normal_update(f);
}
}
+ if (is_new) {
+ bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */
+ }
- bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */
+ /* -------------------------------------------------------------------- */
+ /* MSelect clears the array elements (avoid adding multiple times).
+ *
+ * Take care to keep this last and not use (v/e/ftable) after this.
+ */
if (me->mselect && me->totselect != 0) {
-
- BMVert **vert_array = MEM_mallocN(sizeof(BMVert *) * bm->totvert, "VSelConv");
- BMEdge **edge_array = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, "ESelConv");
- BMFace **face_array = MEM_mallocN(sizeof(BMFace *) * bm->totface, "FSelConv");
MSelect *msel;
-
-#pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
- {
-#pragma omp section
- { BM_iter_as_array(bm, BM_VERTS_OF_MESH, NULL, (void **)vert_array, bm->totvert); }
-#pragma omp section
- { BM_iter_as_array(bm, BM_EDGES_OF_MESH, NULL, (void **)edge_array, bm->totedge); }
-#pragma omp section
- { BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)face_array, bm->totface); }
- }
-
for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) {
+ BMElem **ele_p;
switch (msel->type) {
case ME_VSEL:
- BM_select_history_store(bm, (BMElem *)vert_array[msel->index]);
+ ele_p = (BMElem **)&vtable[msel->index];
break;
case ME_ESEL:
- BM_select_history_store(bm, (BMElem *)edge_array[msel->index]);
+ ele_p = (BMElem **)&etable[msel->index];
break;
case ME_FSEL:
- BM_select_history_store(bm, (BMElem *)face_array[msel->index]);
+ ele_p = (BMElem **)&ftable[msel->index];
break;
+ default:
+ continue;
}
- }
- MEM_freeN(vert_array);
- MEM_freeN(edge_array);
- MEM_freeN(face_array);
+ if (*ele_p != NULL) {
+ BM_select_history_store_notest(bm, *ele_p);
+ *ele_p = NULL;
+ }
+ }
}
else {
- me->totselect = 0;
- if (me->mselect) {
- MEM_freeN(me->mselect);
- me->mselect = NULL;
- }
+ BM_select_history_clear(bm);
}
MEM_freeN(vtable);
MEM_freeN(etable);
+ if (ftable) {
+ MEM_freeN(ftable);
+ }
}
@@ -945,6 +959,10 @@ void BM_mesh_bm_to_me(
/* propagate edited basis offsets to other shapes */
if (apply_offset) {
add_v3_v3(fp, *ofs_pt++);
+ /* Apply back new coordinates of offsetted shapekeys into BMesh.
+ * Otherwise, in case we call again BM_mesh_bm_to_me on same BMesh, we'll apply diff from previous
+ * call to BM_mesh_bm_to_me, to shapekey values from *original creation of the BMesh*. See T50524. */
+ copy_v3_v3(BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp);
}
fp += 3;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.h b/source/blender/bmesh/intern/bmesh_mesh_conv.h
index 7cbfe2d9210..1974d364171 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.h
@@ -41,11 +41,11 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
struct BMeshFromMeshParams {
- unsigned int calc_face_normal : 1;
+ uint calc_face_normal : 1;
/* add a vertex CD_SHAPE_KEYINDEX layer */
- unsigned int add_key_index : 1;
+ uint add_key_index : 1;
/* set vertex coordinates from the shapekey */
- unsigned int use_shapekey : 1;
+ uint use_shapekey : 1;
/* define the active shape key (index + 1) */
int active_shapekey;
};
@@ -55,7 +55,7 @@ void BM_mesh_bm_from_me(
ATTR_NONNULL(1, 3);
struct BMeshToMeshParams {
- unsigned int calc_tessface : 1;
+ uint calc_tessface : 1;
int64_t cd_mask_extra;
};
void BM_mesh_bm_to_me(
diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c
index 7c9ebc800a3..3a6a3543bc8 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_validate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c
@@ -41,7 +41,7 @@
/* macro which inserts the function name */
-#if defined __GNUC__ || defined __sun
+#if defined __GNUC__
# define ERRMSG(format, args...) { fprintf(stderr, "%s: " format ", " AT "\n", __func__, ##args); errtot++; } (void)0
#else
# define ERRMSG(format, ...) { fprintf(stderr, "%s: " format ", " AT "\n", __func__, __VA_ARGS__); errtot++; } (void)0
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 500da6b8788..1cd51528e06 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -234,7 +234,7 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_de
if (l_a->v == l_b->v) {
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
- bmesh_loop_reverse(bm, l_b->f, cd_loop_mdisp_offset, true);
+ bmesh_kernel_loop_reverse(bm, l_b->f, cd_loop_mdisp_offset, true);
}
BMFace *faces[2] = {l_a->f, l_b->f};
@@ -288,9 +288,9 @@ BMFace *BM_face_split(
}
#ifdef USE_BMESH_HOLES
- f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, no_double);
+ f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, r_l, NULL, example, no_double);
#else
- f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, no_double);
+ f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, r_l, example, no_double);
#endif
if (f_new) {
@@ -370,19 +370,19 @@ BMFace *BM_face_split_n(
f_tmp = BM_face_copy(bm, bm, f, true, true);
#ifdef USE_BMESH_HOLES
- f_new = bmesh_sfme(bm, f, l_a, l_b, &l_new, NULL, example, false);
+ f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, &l_new, NULL, example, false);
#else
- f_new = bmesh_sfme(bm, f, l_a, l_b, &l_new, example, false);
+ f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, &l_new, example, false);
#endif
- /* bmesh_sfme returns in 'l_new' a Loop for f_new going from 'v_a' to 'v_b'.
+ /* bmesh_kernel_split_face_make_edge returns in 'l_new' a Loop for f_new going from 'v_a' to 'v_b'.
* The radial_next is for 'f' and goes from 'v_b' to 'v_a' */
if (f_new) {
e = l_new->e;
for (i = 0; i < n; i++) {
- v_new = bmesh_semv(bm, v_b, e, &e_new);
+ v_new = bmesh_kernel_split_edge_make_vert(bm, v_b, e, &e_new);
BLI_assert(v_new != NULL);
- /* bmesh_semv returns in 'e_new' the edge going from 'v_new' to 'v_b' */
+ /* bmesh_kernel_split_edge_make_vert returns in 'e_new' the edge going from 'v_new' to 'v_b' */
copy_v3_v3(v_new->co, cos[i]);
/* interpolate the loop data for the loops with (v == v_new), using orig face */
@@ -507,7 +507,7 @@ BMEdge *BM_vert_collapse_faces(
/* single face or no faces */
/* same as BM_vert_collapse_edge() however we already
* have vars to perform this operation so don't call. */
- e_new = bmesh_jekv(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
+ e_new = bmesh_kernel_join_edge_kill_vert(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
/* e_new = BM_edge_exists(tv, tv2); */ /* same as return above */
}
@@ -542,7 +542,7 @@ BMEdge *BM_vert_collapse_edge(
BMVert *tv2 = BM_edge_other_vert(e2, v_kill);
if (tv2) {
/* only action, other calls here only get the edge to return */
- e_new = bmesh_jekv(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
+ e_new = bmesh_kernel_join_edge_kill_vert(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
}
}
}
@@ -564,7 +564,7 @@ BMVert *BM_edge_collapse(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
const bool do_del, const bool kill_degenerate_faces)
{
- return bmesh_jvke(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
+ return bmesh_kernel_join_vert_kill_edge(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
}
/**
@@ -616,7 +616,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
}
v_other = BM_edge_other_vert(e, v);
- v_new = bmesh_semv(bm, v, e, &e_new);
+ v_new = bmesh_kernel_split_edge_make_vert(bm, v, e, &e_new);
if (r_e != NULL) {
*r_e = e_new;
}
@@ -1090,23 +1090,18 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
/**
* \brief Rip a single face from a vertex fan
*/
-BMVert *BM_face_vert_separate(BMesh *bm, BMFace *sf, BMVert *sv)
+BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep)
{
- return bmesh_urmv(bm, sf, sv);
+ return bmesh_kernel_unglue_region_make_vert(bm, l_sep);
}
-/**
- * \brief Rip a single face from a vertex fan
- *
- * \note same as #BM_face_vert_separate but faster (avoids a loop lookup)
- */
-BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *sl)
+BMVert *BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep)
{
- return bmesh_urmv_loop(bm, sl);
+ return bmesh_kernel_unglue_region_make_vert_multi_isolated(bm, l_sep);
}
-BMVert *BM_face_loop_separate_multi(
- BMesh *bm, BMLoop **larr, int larr_len)
+BMVert *BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len)
{
- return bmesh_urmv_loop_multi(bm, larr, larr_len);
+ return bmesh_kernel_unglue_region_make_vert_multi(bm, larr, larr_len);
}
+
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index 5e95e9a2cc7..330a714418d 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -86,9 +86,8 @@ enum {
};
-BMVert *BM_face_vert_separate(BMesh *bm, BMFace *sf, BMVert *sv);
-BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *sl);
-BMVert *BM_face_loop_separate_multi(
- BMesh *bm, BMLoop **larr, int larr_len);
+BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep);
+BMVert *BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep);
+BMVert *BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len);
#endif /* __BMESH_MODS_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 0d0fdda2c4c..4f48dafd211 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1037,7 +1037,7 @@ static BMOpDefine bmo_extrude_face_region_def = {
/* slots_in */
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* edges and faces */
{"edges_exclude", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_EMPTY}},
- {"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry */
+ {"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry (requires ``geom`` to include edges). */
{"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */
{{'\0'}},
},
@@ -1284,7 +1284,7 @@ static BMOpDefine bmo_bisect_plane_def = {
{"clear_inner", BMO_OP_SLOT_BOOL}, /* when enabled. remove all geometry on the negative side of the plane */
{{'\0'}},
},
- {{"geom_cut.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE}}, /* output new geometry from the cut */
+ {{"geom_cut.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE}}, /* output geometry aligned with the plane (new and existing) */
{"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input and output geometry (result of cut) */
{{'\0'}}},
bmo_bisect_plane_exec,
@@ -1684,7 +1684,7 @@ static BMOpDefine bmo_create_circle_def = {
{{"cap_ends", BMO_OP_SLOT_BOOL}, /* whether or not to fill in the ends with faces */
{"cap_tris", BMO_OP_SLOT_BOOL}, /* fill ends with triangles instead of ngons */
{"segments", BMO_OP_SLOT_INT},
- {"diameter", BMO_OP_SLOT_FLT}, /* diameter of one end */
+ {"radius", BMO_OP_SLOT_FLT}, /* Radius of the circle. */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
{"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
@@ -1741,6 +1741,8 @@ static BMOpDefine bmo_bevel_def = {
},
/* slots_out */
{{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */
+ {"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* output edges */
+ {"verts.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* output verts */
{{'\0'}},
},
@@ -1912,7 +1914,6 @@ static BMOpDefine bmo_wireframe_def = {
{"use_even_offset", BMO_OP_SLOT_BOOL},
{"use_crease", BMO_OP_SLOT_BOOL},
{"crease_weight", BMO_OP_SLOT_FLT},
- {"thickness", BMO_OP_SLOT_FLT},
{"use_relative_offset", BMO_OP_SLOT_BOOL},
{"material_offset", BMO_OP_SLOT_INT},
{{'\0'}},
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index 706a7f74ed2..44445aae25a 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -128,7 +128,7 @@ void BMO_pop(BMesh *bm)
static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args)
{
BMOpSlot *slot;
- unsigned int i;
+ uint i;
for (i = 0; slot_types[i].type; i++) {
slot = &slot_args[i];
slot->slot_name = slot_types[i].name;
@@ -149,7 +149,7 @@ static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args
static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args)
{
BMOpSlot *slot;
- unsigned int i;
+ uint i;
for (i = 0; slot_types[i].type; i++) {
slot = &slot_args[i];
switch (slot->slot_type) {
@@ -311,9 +311,9 @@ void _bmo_slot_copy(
}
else {
/* check types */
- const unsigned int tot = slot_src->len;
- unsigned int i;
- unsigned int out = 0;
+ const uint tot = slot_src->len;
+ uint i;
+ uint out = 0;
BMElem **ele_src = (BMElem **)slot_src->data.buf;
for (i = 0; i < tot; i++, ele_src++) {
if ((*ele_src)->head.htype & dst_elem_flag) {
@@ -333,8 +333,8 @@ void _bmo_slot_copy(
}
else {
/* only copy compatible elements */
- const unsigned int tot = slot_src->len;
- unsigned int i;
+ const uint tot = slot_src->len;
+ uint i;
BMElem **ele_src = (BMElem **)slot_src->data.buf;
BMElem **ele_dst = (BMElem **)slot_dst->data.buf;
for (i = 0; i < tot; i++, ele_src++) {
@@ -1639,8 +1639,8 @@ static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], cons
int BMO_opcode_from_opname(const char *opname)
{
- const unsigned int tot = bmo_opdefines_total;
- unsigned int i;
+ const uint tot = bmo_opdefines_total;
+ uint i;
for (i = 0; i < tot; i++) {
if (STREQ(bmo_opdefines[i]->opname, opname)) {
return i;
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index 0a4fb1d56a4..b670f31ad9f 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -141,12 +141,19 @@ void BM_mesh_esubdivide(
const short use_only_quads,
const int seed);
-void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsigned int y_segments, const short oflag);
-void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag);
-void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, const short oflag);
+void BM_mesh_calc_uvs_grid(
+ BMesh *bm, const uint x_segments, const uint y_segments,
+ const short oflag, const int cd_loop_uv_offset);
+void BM_mesh_calc_uvs_sphere(
+ BMesh *bm,
+ const short oflag, const int cd_loop_uv_offset);
+void BM_mesh_calc_uvs_circle(
+ BMesh *bm, float mat[4][4], const float radius,
+ const short oflag, const int cd_loop_uv_offset);
void BM_mesh_calc_uvs_cone(
BMesh *bm, float mat[4][4],
- const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, const short oflag);
+ const float radius_top, const float radius_bottom, const int segments, const bool cap_ends,
+ const short oflag, const int cd_loop_uv_offset);
void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag);
#include "intern/bmesh_operator_api_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 6acd790fc0c..7b9d17b27b5 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -39,6 +39,8 @@
#include "BLI_polyfill2d.h"
#include "BLI_polyfill2d_beautify.h"
#include "BLI_linklist.h"
+#include "BLI_edgehash.h"
+#include "BLI_heap.h"
#include "bmesh.h"
#include "bmesh_tools.h"
@@ -132,7 +134,7 @@ static void bm_face_calc_poly_center_mean_vertex_cos(
*/
void BM_face_calc_tessellation(
const BMFace *f, const bool use_fixed_quad,
- BMLoop **r_loops, unsigned int (*r_index)[3])
+ BMLoop **r_loops, uint (*r_index)[3])
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter;
@@ -196,7 +198,7 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
* but without this we can't be sure the point is inside a concave face. */
const int tottri = f->len - 2;
BMLoop **loops = BLI_array_alloca(loops, f->len);
- unsigned int (*index)[3] = BLI_array_alloca(index, tottri);
+ uint (*index)[3] = BLI_array_alloca(index, tottri);
int j;
int j_best = 0; /* use as fallback when unset */
float area_best = -1.0f;
@@ -575,11 +577,11 @@ void BM_face_calc_center_mean_weighted(const BMFace *f, float r_cent[3])
* Rotates a polygon so that it's
* normal is pointing towards the mesh Z axis
*/
-void poly_rotate_plane(const float normal[3], float (*verts)[3], const unsigned int nverts)
+void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts)
{
float mat[3][3];
float co[3];
- unsigned int i;
+ uint i;
co[2] = 0.0f;
@@ -844,7 +846,7 @@ void BM_face_normal_flip_ex(
BMesh *bm, BMFace *f,
const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
{
- bmesh_loop_reverse(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
+ bmesh_kernel_loop_reverse(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
negate_v3(f->no);
}
@@ -941,7 +943,7 @@ void BM_face_triangulate(
{
BMLoop **loops = BLI_array_alloca(loops, f->len);
- unsigned int (*tris)[3] = BLI_array_alloca(tris, f->len);
+ uint (*tris)[3] = BLI_array_alloca(tris, f->len);
const int totfilltri = f->len - 2;
const int last_tri = f->len - 3;
int i;
@@ -1425,7 +1427,7 @@ void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptri
float axis_mat[3][3];
float (*projverts)[2];
- unsigned int (*tris)[3];
+ uint (*tris)[3];
const int totfilltri = efa->len - 2;
@@ -1451,7 +1453,7 @@ void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptri
for (j = 0; j < totfilltri; j++) {
BMLoop **l_ptr = looptris[i++];
- unsigned int *tri = tris[j];
+ uint *tri = tris[j];
l_ptr[0] = l_arr[tri[0]];
l_ptr[1] = l_arr[tri[1]];
@@ -1474,3 +1476,147 @@ void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptri
#undef USE_TESSFACE_SPEEDUP
}
+
+
+/**
+ * A version of #BM_mesh_calc_tessellation that avoids degenerate triangles.
+ */
+void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot)
+{
+ /* this assumes all faces can be scan-filled, which isn't always true,
+ * worst case we over alloc a little which is acceptable */
+#ifndef NDEBUG
+ const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
+#endif
+
+ BMIter iter;
+ BMFace *efa;
+ int i = 0;
+
+ MemArena *pf_arena = NULL;
+
+ /* use_beauty */
+ Heap *pf_heap = NULL;
+ EdgeHash *pf_ehash = NULL;
+
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ /* don't consider two-edged faces */
+ if (UNLIKELY(efa->len < 3)) {
+ /* do nothing */
+ }
+ else if (efa->len == 3) {
+ BMLoop *l;
+ BMLoop **l_ptr = looptris[i++];
+ l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
+ l_ptr[1] = l = l->next;
+ l_ptr[2] = l->next;
+ }
+ else if (efa->len == 4) {
+ BMLoop *l_v1 = BM_FACE_FIRST_LOOP(efa);
+ BMLoop *l_v2 = l_v1->next;
+ BMLoop *l_v3 = l_v2->next;
+ BMLoop *l_v4 = l_v1->prev;
+
+ /* #BM_verts_calc_rotate_beauty performs excessive checks we don't need!
+ * It's meant for rotating edges, it also calculates a new normal.
+ *
+ * Use #BLI_polyfill_beautify_quad_rotate_calc since we have the normal.
+ */
+#if 0
+ const bool split_13 = (BM_verts_calc_rotate_beauty(
+ l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) < 0.0f);
+#else
+ float axis_mat[3][3], v_quad[4][2];
+ axis_dominant_v3_to_m3(axis_mat, efa->no);
+ mul_v2_m3v3(v_quad[0], axis_mat, l_v1->v->co);
+ mul_v2_m3v3(v_quad[1], axis_mat, l_v2->v->co);
+ mul_v2_m3v3(v_quad[2], axis_mat, l_v3->v->co);
+ mul_v2_m3v3(v_quad[3], axis_mat, l_v4->v->co);
+
+ const bool split_13 = BLI_polyfill_beautify_quad_rotate_calc(
+ v_quad[0], v_quad[1], v_quad[2], v_quad[3]) < 0.0f;
+#endif
+
+ BMLoop **l_ptr_a = looptris[i++];
+ BMLoop **l_ptr_b = looptris[i++];
+ if (split_13) {
+ l_ptr_a[0] = l_v1;
+ l_ptr_a[1] = l_v2;
+ l_ptr_a[2] = l_v3;
+
+ l_ptr_b[0] = l_v1;
+ l_ptr_b[1] = l_v3;
+ l_ptr_b[2] = l_v4;
+ }
+ else {
+ l_ptr_a[0] = l_v1;
+ l_ptr_a[1] = l_v2;
+ l_ptr_a[2] = l_v4;
+
+ l_ptr_b[0] = l_v2;
+ l_ptr_b[1] = l_v3;
+ l_ptr_b[2] = l_v4;
+ }
+ }
+ else {
+ int j;
+
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ BMLoop **l_arr;
+
+ float axis_mat[3][3];
+ float (*projverts)[2];
+ unsigned int (*tris)[3];
+
+ const int totfilltri = efa->len - 2;
+
+ if (UNLIKELY(pf_arena == NULL)) {
+ pf_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ }
+
+ tris = BLI_memarena_alloc(pf_arena, sizeof(*tris) * totfilltri);
+ l_arr = BLI_memarena_alloc(pf_arena, sizeof(*l_arr) * efa->len);
+ projverts = BLI_memarena_alloc(pf_arena, sizeof(*projverts) * efa->len);
+
+ axis_dominant_v3_to_m3_negate(axis_mat, efa->no);
+
+ j = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ l_arr[j] = l_iter;
+ mul_v2_m3v3(projverts[j], axis_mat, l_iter->v->co);
+ j++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ BLI_polyfill_calc_arena((const float (*)[2])projverts, efa->len, 1, tris, pf_arena);
+
+ BLI_polyfill_beautify((const float (*)[2])projverts, efa->len, tris, pf_arena, pf_heap, pf_ehash);
+
+ for (j = 0; j < totfilltri; j++) {
+ BMLoop **l_ptr = looptris[i++];
+ unsigned int *tri = tris[j];
+
+ l_ptr[0] = l_arr[tri[0]];
+ l_ptr[1] = l_arr[tri[1]];
+ l_ptr[2] = l_arr[tri[2]];
+ }
+
+ BLI_memarena_clear(pf_arena);
+ }
+ }
+
+ if (pf_arena) {
+ BLI_memarena_free(pf_arena);
+
+ BLI_heap_free(pf_heap, NULL);
+ BLI_edgehash_free(pf_ehash, NULL);
+ }
+
+ *r_looptris_tot = i;
+
+ BLI_assert(i <= looptris_tot);
+
+}
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 1e50a504875..313caac1243 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -33,10 +33,11 @@ struct Heap;
#include "BLI_compiler_attrs.h"
void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot);
+void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot);
void BM_face_calc_tessellation(
const BMFace *f, const bool use_fixed_quad,
- BMLoop **r_loops, unsigned int (*r_index)[3]);
+ BMLoop **r_loops, uint (*r_index)[3]);
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]);
float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
float BM_face_calc_normal_vcos(
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index 6ce7c100b0d..8a3cb329610 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -32,7 +32,7 @@
#include "BLI_memarena.h"
#include "BLI_array.h"
#include "BLI_alloca.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BLI_linklist_stack.h"
#include "BLI_sort.h"
#include "BLI_sort_utils.h"
@@ -62,15 +62,16 @@
#define EDGE_NET _FLAG_WALK
/* tag verts we've visit */
#define VERT_VISIT _FLAG_WALK
+#define VERT_IN_QUEUE _FLAG_WALK_ALT
struct VertOrder {
float angle;
BMVert *v;
};
-static unsigned int bm_edge_flagged_radial_count(BMEdge *e)
+static uint bm_edge_flagged_radial_count(BMEdge *e)
{
- unsigned int count = 0;
+ uint count = 0;
BMLoop *l;
if ((l = e->l)) {
@@ -133,7 +134,7 @@ static bool bm_face_split_edgenet_find_loop_pair(
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);
+ const uint count = bm_edge_flagged_radial_count(e);
if (count == 1) {
BLI_SMALLSTACK_PUSH(edges_boundary, e);
edges_boundary_len++;
@@ -238,7 +239,7 @@ static bool bm_face_split_edgenet_find_loop_pair_exists(
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);
+ const uint count = bm_edge_flagged_radial_count(e);
if (count == 1) {
edges_boundary_len++;
}
@@ -274,7 +275,7 @@ static bool bm_face_split_edgenet_find_loop_pair_exists(
static bool bm_face_split_edgenet_find_loop_walk(
BMVert *v_init, const float face_normal[3],
/* cache to avoid realloc every time */
- struct VertOrder *edge_order, const unsigned int edge_order_len,
+ struct VertOrder *edge_order, const uint edge_order_len,
BMEdge *e_pair[2])
{
/* fast-path for the common case (avoid push-pop).
@@ -381,7 +382,7 @@ walk_nofork:
/* sort by angle if needed */
if (STACK_SIZE(edge_order) > 1) {
- unsigned int j;
+ uint j;
BMVert *v_prev = BM_edge_other_vert(v->e, v);
for (j = 0; j < STACK_SIZE(edge_order); j++) {
@@ -420,7 +421,7 @@ finally:
static bool bm_face_split_edgenet_find_loop(
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,
+ struct VertOrder *edge_order, const uint edge_order_len,
BMVert **r_face_verts, int *r_face_verts_len)
{
BMEdge *e_pair[2];
@@ -434,7 +435,7 @@ static bool bm_face_split_edgenet_find_loop(
(bm_edge_flagged_radial_count(e_pair[1]) == 1));
if (bm_face_split_edgenet_find_loop_walk(v_init, face_normal, edge_order, edge_order_len, e_pair)) {
- unsigned int i = 0;
+ uint i = 0;
r_face_verts[i++] = v_init;
v = BM_edge_other_vert(e_pair[1], v_init);
@@ -474,7 +475,7 @@ bool BM_face_split_edgenet(
int i;
struct VertOrder *edge_order;
- const unsigned int edge_order_len = edge_net_len + 2;
+ const uint edge_order_len = edge_net_len + 2;
BMVert *v;
@@ -512,13 +513,21 @@ bool BM_face_split_edgenet(
} while ((l_iter = l_iter->next) != l_first);
#endif
+ /* Note: 'VERT_IN_QUEUE' is often not needed at all,
+ * however in rare cases verts are added multiple times to the queue,
+ * that on it's own is harmless but in _very_ rare cases,
+ * the queue will overflow its maximum size,
+ * so we better be strict about this! see: T51539 */
for (i = 0; i < edge_net_len; i++) {
BM_ELEM_API_FLAG_ENABLE(edge_net[i], EDGE_NET);
+ BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v1, VERT_IN_QUEUE);
+ BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v2, VERT_IN_QUEUE);
}
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET);
+ BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_IN_QUEUE);
} while ((l_iter = l_iter->next) != l_first);
float face_normal_matrix[3][3];
@@ -527,8 +536,10 @@ bool BM_face_split_edgenet(
/* any vert can be used to begin with */
STACK_PUSH(vert_queue, l_first->v);
+ BM_ELEM_API_FLAG_ENABLE(l_first->v, VERT_IN_QUEUE);
while ((v = STACK_POP(vert_queue))) {
+ BM_ELEM_API_FLAG_DISABLE(v, VERT_IN_QUEUE);
if (bm_face_split_edgenet_find_loop(
v, f->no, face_normal_matrix,
edge_order, edge_order_len, face_verts, &face_verts_len))
@@ -558,8 +569,12 @@ bool BM_face_split_edgenet(
* (verts between boundary and manifold edges) */
l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
do {
- if (bm_face_split_edgenet_find_loop_pair_exists(l_iter->v)) {
+ /* Avoid adding to queue multiple times (not common but happens). */
+ if (!BM_ELEM_API_FLAG_TEST(l_iter->v, VERT_IN_QUEUE) &&
+ bm_face_split_edgenet_find_loop_pair_exists(l_iter->v))
+ {
STACK_PUSH(vert_queue, l_iter->v);
+ BM_ELEM_API_FLAG_ENABLE(l_iter->v, VERT_IN_QUEUE);
}
} while ((l_iter = l_iter->next) != l_first);
}
@@ -710,10 +725,30 @@ BLI_INLINE bool edge_isect_verts_point_2d(
const BMEdge *e, const BMVert *v_a, const BMVert *v_b,
float r_isect[2])
{
- return ((isect_seg_seg_v2_point(v_a->co, v_b->co, e->v1->co, e->v2->co, r_isect) == 1) &&
+ /* This bias seems like it could be too large,
+ * mostly its not needed, see T52329 for example where it is. */
+ const float endpoint_bias = 1e-4f;
+ return ((isect_seg_seg_v2_point_ex(v_a->co, v_b->co, e->v1->co, e->v2->co, endpoint_bias, r_isect) == 1) &&
((e->v1 != v_a) && (e->v2 != v_a) && (e->v1 != v_b) && (e->v2 != v_b)));
}
+BLI_INLINE int axis_pt_cmp(const float pt_a[2], const float pt_b[2])
+{
+ if (pt_a[0] < pt_b[0]) {
+ return -1;
+ }
+ if (pt_a[0] > pt_b[0]) {
+ return 1;
+ }
+ if (pt_a[1] < pt_b[1]) {
+ return -1;
+ }
+ if (pt_a[1] > pt_b[1]) {
+ return 1;
+ }
+ return 0;
+}
+
/**
* Represents isolated edge-links,
* each island owns contiguous slices of the vert array.
@@ -721,20 +756,21 @@ BLI_INLINE bool edge_isect_verts_point_2d(
*/
struct EdgeGroupIsland {
LinkNode edge_links; /* keep first */
- unsigned int vert_len, edge_len;
+ uint vert_len, edge_len;
/* Set the following vars once we have >1 groups */
/* when when an edge in a previous group connects to this one,
* so theres no need to create one pointing back. */
- unsigned int has_prev_edge : 1;
+ uint has_prev_edge : 1;
/* verts in the group which has the lowest & highest values,
* the lower vertex is connected to the first edge */
struct {
BMVert *min, *max;
/* used for sorting only */
- float min_axis;
+ float min_axis[2];
+ float max_axis[2];
} vert_span;
};
@@ -743,12 +779,11 @@ static int group_min_cmp_fn(const void *p1, const void *p2)
const struct EdgeGroupIsland *g1 = *(struct EdgeGroupIsland **)p1;
const struct EdgeGroupIsland *g2 = *(struct EdgeGroupIsland **)p2;
/* min->co[SORT_AXIS] hasn't been applied yet */
- const float f1 = g1->vert_span.min_axis;
- const float f2 = g2->vert_span.min_axis;
-
- if (f1 < f2) return -1;
- if (f1 > f2) return 1;
- else return 0;
+ int test = axis_pt_cmp(g1->vert_span.min_axis, g2->vert_span.min_axis);
+ if (UNLIKELY(test == 0)) {
+ test = axis_pt_cmp(g1->vert_span.max_axis, g2->vert_span.max_axis);
+ }
+ return test;
}
struct Edges_VertVert_BVHTreeTest {
@@ -758,7 +793,7 @@ struct Edges_VertVert_BVHTreeTest {
BMVert *v_origin;
BMVert *v_other;
- const unsigned int *vert_range;
+ const uint *vert_range;
};
struct Edges_VertRay_BVHTreeTest {
@@ -766,7 +801,7 @@ struct Edges_VertRay_BVHTreeTest {
BMVert *v_origin;
- const unsigned int *vert_range;
+ const uint *vert_range;
};
static void bvhtree_test_edges_isect_2d_vert_cb(
@@ -831,12 +866,12 @@ static void bvhtree_test_edges_isect_2d_ray_cb(
struct EdgeGroup_FindConnection_Args {
BVHTree *bvhtree;
BMEdge **edge_arr;
- unsigned int edge_arr_len;
+ uint edge_arr_len;
BMEdge **edge_arr_new;
- unsigned int edge_arr_new_len;
+ uint edge_arr_new_len;
- const unsigned int *vert_range;
+ const uint *vert_range;
};
static BMEdge *test_edges_isect_2d_vert(
@@ -869,7 +904,7 @@ static BMEdge *test_edges_isect_2d_vert(
/* check existing connections (no spatial optimization here since we're continually adding). */
if (LIKELY(index == -1)) {
float t_best = 1.0f;
- for (unsigned int i = 0; i < args->edge_arr_new_len; i++) {
+ for (uint i = 0; i < args->edge_arr_new_len; i++) {
float co_isect[2];
if (UNLIKELY(edge_isect_verts_point_2d(args->edge_arr_new[i], v_origin, v_other, co_isect))) {
const float t_test = line_point_factor_v2(co_isect, v_origin->co, v_other->co);
@@ -914,7 +949,7 @@ static BMEdge *test_edges_isect_2d_ray(
/* check existing connections (no spatial optimization here since we're continually adding). */
if (LIKELY(index != -1)) {
- for (unsigned int i = 0; i < args->edge_arr_new_len; i++) {
+ for (uint i = 0; i < args->edge_arr_new_len; i++) {
BMEdge *e = args->edge_arr_new[i];
float dist_new;
if (isect_ray_seg_v2(v_origin->co, dir, e->v1->co, e->v2->co, &dist_new, NULL)) {
@@ -978,8 +1013,8 @@ static int bm_face_split_edgenet_find_connection(
for (int j = 0; j < 2; j++) {
BMVert *v_iter = v_pair[j];
if (BM_elem_flag_test(v_iter, VERT_IS_VALID)) {
- if (direction_sign ? (v_iter->co[SORT_AXIS] >= v_origin->co[SORT_AXIS]) :
- (v_iter->co[SORT_AXIS] <= v_origin->co[SORT_AXIS]))
+ if (direction_sign ? (v_iter->co[SORT_AXIS] > v_origin->co[SORT_AXIS]) :
+ (v_iter->co[SORT_AXIS] < v_origin->co[SORT_AXIS]))
{
BLI_SMALLSTACK_PUSH(vert_search, v_iter);
BLI_SMALLSTACK_PUSH(vert_blacklist, v_iter);
@@ -1031,7 +1066,7 @@ static BMVert *bm_face_split_edgenet_partial_connect(BMesh *bm, BMVert *v_delimi
/* initial check - see if we have 3+ flagged edges attached to 'v_delimit'
* if not, we can early exit */
LinkNode *e_delimit_list = NULL;
- unsigned int e_delimit_list_len = 0;
+ uint e_delimit_list_len = 0;
#define EDGE_NOT_IN_STACK BM_ELEM_INTERNAL_TAG
#define VERT_NOT_IN_STACK BM_ELEM_INTERNAL_TAG
@@ -1169,10 +1204,10 @@ static bool bm_vert_partial_connect_check_overlap(
*/
bool BM_face_split_edgenet_connect_islands(
BMesh *bm,
- BMFace *f, BMEdge **edge_net_init, const unsigned int edge_net_init_len,
+ BMFace *f, BMEdge **edge_net_init, const uint edge_net_init_len,
bool use_partial_connect,
MemArena *mem_arena,
- BMEdge ***r_edge_net_new, unsigned int *r_edge_net_new_len)
+ BMEdge ***r_edge_net_new, uint *r_edge_net_new_len)
{
/* -------------------------------------------------------------------- */
/* This function has 2 main parts.
@@ -1186,7 +1221,7 @@ bool BM_face_split_edgenet_connect_islands(
* (avoid thrashing the area when the initial check isn't so intensive on the stack).
*/
- const unsigned int edge_arr_len = (unsigned int)edge_net_init_len + (unsigned int)f->len;
+ const uint edge_arr_len = (uint)edge_net_init_len + (uint)f->len;
BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len);
bool ok = false;
@@ -1197,7 +1232,7 @@ bool BM_face_split_edgenet_connect_islands(
#define VERT_NOT_IN_STACK BM_ELEM_INTERNAL_TAG
{
- unsigned int i = edge_net_init_len;
+ uint i = edge_net_init_len;
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
@@ -1206,7 +1241,7 @@ bool BM_face_split_edgenet_connect_islands(
BLI_assert(i == edge_arr_len);
}
- for (unsigned int i = 0; i < edge_arr_len; i++) {
+ for (uint i = 0; i < edge_arr_len; i++) {
BM_elem_flag_enable(edge_arr[i], EDGE_NOT_IN_STACK);
BM_elem_flag_enable(edge_arr[i]->v1, VERT_NOT_IN_STACK);
BM_elem_flag_enable(edge_arr[i]->v2, VERT_NOT_IN_STACK);
@@ -1224,12 +1259,12 @@ bool BM_face_split_edgenet_connect_islands(
struct {
struct TempVertPair *list;
- unsigned int len;
+ uint len;
int *remap; /* temp -> orig mapping */
} temp_vert_pairs = {NULL};
if (use_partial_connect) {
- for (unsigned int i = 0; i < edge_net_init_len; i++) {
+ for (uint i = 0; i < edge_net_init_len; i++) {
for (unsigned j = 0; j < 2; j++) {
BMVert *v_delimit = (&edge_arr[i]->v1)[j];
BMVert *v_other;
@@ -1254,19 +1289,19 @@ bool BM_face_split_edgenet_connect_islands(
- unsigned int group_arr_len = 0;
+ uint group_arr_len = 0;
LinkNode *group_head = NULL;
{
/* scan 'edge_arr' backwards so the outer face boundary is handled first
* (since its likely to be the largest) */
- unsigned int edge_index = (edge_arr_len - 1);
- unsigned int edge_in_group_tot = 0;
+ uint edge_index = (edge_arr_len - 1);
+ uint edge_in_group_tot = 0;
BLI_SMALLSTACK_DECLARE(vstack, BMVert *);
while (true) {
LinkNode *edge_links = NULL;
- unsigned int unique_verts_in_group = 0, unique_edges_in_group = 0;
+ uint unique_verts_in_group = 0, unique_edges_in_group = 0;
/* list of groups */
BLI_assert(BM_elem_flag_test(edge_arr[edge_index]->v1, VERT_NOT_IN_STACK));
@@ -1333,7 +1368,7 @@ bool BM_face_split_edgenet_connect_islands(
#define VERT_IN_ARRAY BM_ELEM_INTERNAL_TAG
struct EdgeGroupIsland **group_arr = BLI_memarena_alloc(mem_arena, sizeof(*group_arr) * group_arr_len);
- unsigned int vert_arr_len = 0;
+ uint vert_arr_len = 0;
/* sort groups by lowest value vertex */
{
/* fill 'groups_arr' in reverse order so the boundary face is first */
@@ -1345,8 +1380,8 @@ bool BM_face_split_edgenet_connect_islands(
/* init with *any* different verts */
g->vert_span.min = ((BMEdge *)edge_links->link)->v1;
g->vert_span.max = ((BMEdge *)edge_links->link)->v2;
- float min_axis = FLT_MAX;
- float max_axis = -FLT_MAX;
+ float min_axis[2] = {FLT_MAX, FLT_MAX};
+ float max_axis[2] = {-FLT_MAX, -FLT_MAX};
do {
BMEdge *e = edge_links->link;
@@ -1357,24 +1392,29 @@ bool BM_face_split_edgenet_connect_islands(
BLI_assert(v_iter->head.htype == BM_VERT);
/* ideally we could use 'v_iter->co[SORT_AXIS]' here,
* but we need to sort the groups before setting the vertex array order */
+ const float axis_value[2] = {
#if SORT_AXIS == 0
- const float axis_value = dot_m3_v3_row_x(axis_mat, v_iter->co);
+ dot_m3_v3_row_x(axis_mat, v_iter->co),
+ dot_m3_v3_row_y(axis_mat, v_iter->co),
#else
- const float axis_value = dot_m3_v3_row_y(axis_mat, v_iter->co);
+ dot_m3_v3_row_y(axis_mat, v_iter->co),
+ dot_m3_v3_row_x(axis_mat, v_iter->co),
#endif
+ };
- if (axis_value < min_axis) {
+ if (axis_pt_cmp(axis_value, min_axis) == -1) {
g->vert_span.min = v_iter;
- min_axis = axis_value;
+ copy_v2_v2(min_axis, axis_value);
}
- if (axis_value > max_axis ) {
+ if (axis_pt_cmp(axis_value, max_axis) == 1) {
g->vert_span.max = v_iter;
- max_axis = axis_value;
+ copy_v2_v2(max_axis, axis_value);
}
}
} while ((edge_links = edge_links->next));
- g->vert_span.min_axis = min_axis;
+ copy_v2_v2(g->vert_span.min_axis, min_axis);
+ copy_v2_v2(g->vert_span.max_axis, max_axis);
g->has_prev_edge = false;
@@ -1389,7 +1429,7 @@ bool BM_face_split_edgenet_connect_islands(
/* we don't know how many unique verts there are connecting the edges, so over-alloc */
BMVert **vert_arr = BLI_memarena_alloc(mem_arena, sizeof(*vert_arr) * vert_arr_len);
/* map vertex -> group index */
- unsigned int *verts_group_table = BLI_memarena_alloc(mem_arena, sizeof(*verts_group_table) * vert_arr_len);
+ uint *verts_group_table = BLI_memarena_alloc(mem_arena, sizeof(*verts_group_table) * vert_arr_len);
float (*vert_coords_backup)[3] = BLI_memarena_alloc(mem_arena, sizeof(*vert_coords_backup) * vert_arr_len);
@@ -1398,7 +1438,7 @@ bool BM_face_split_edgenet_connect_islands(
const float f_co_ref[3] = {UNPACK3(BM_FACE_FIRST_LOOP(f)->v->co)};
int v_index = 0; /* global vert index */
- for (unsigned int g_index = 0; g_index < group_arr_len; g_index++) {
+ for (uint g_index = 0; g_index < group_arr_len; g_index++) {
LinkNode *edge_links = group_arr[g_index]->edge_links.link;
do {
BMEdge *e = edge_links->link;
@@ -1434,9 +1474,11 @@ bool BM_face_split_edgenet_connect_islands(
bm->elem_index_dirty |= BM_VERT;
- /* Now create bvh tree*/
- BVHTree *bvhtree = BLI_bvhtree_new(edge_arr_len, 0.0f, 8, 8);
- for (unsigned int i = 0; i < edge_arr_len; i++) {
+ /* Now create bvh tree
+ *
+ * Note that a large epsilon is used because meshes with dimensions of around 100+ need it. see T52329. */
+ BVHTree *bvhtree = BLI_bvhtree_new(edge_arr_len, 1e-4f, 8, 8);
+ for (uint i = 0; i < edge_arr_len; i++) {
const float e_cos[2][3] = {
{UNPACK2(edge_arr[i]->v1->co), 0.0f},
{UNPACK2(edge_arr[i]->v2->co), 0.0f},
@@ -1465,15 +1507,15 @@ bool BM_face_split_edgenet_connect_islands(
/* Create connections between groups */
/* may be an over-alloc, but not by much */
- unsigned int edge_net_new_len = (unsigned int)edge_net_init_len + ((group_arr_len - 1) * 2);
+ uint edge_net_new_len = (uint)edge_net_init_len + ((group_arr_len - 1) * 2);
BMEdge **edge_net_new = BLI_memarena_alloc(mem_arena, sizeof(*edge_net_new) * edge_net_new_len);
memcpy(edge_net_new, edge_net_init, sizeof(*edge_net_new) * (size_t)edge_net_init_len);
{
- unsigned int edge_net_new_index = edge_net_init_len;
+ uint edge_net_new_index = edge_net_init_len;
/* start-end of the verts in the current group */
- unsigned int vert_range[2];
+ uint vert_range[2];
vert_range[0] = 0;
vert_range[1] = group_arr[0]->vert_len;
@@ -1492,7 +1534,7 @@ bool BM_face_split_edgenet_connect_islands(
.vert_range = vert_range,
};
- for (unsigned int g_index = 1; g_index < group_arr_len; g_index++) {
+ for (uint g_index = 1; g_index < group_arr_len; g_index++) {
struct EdgeGroupIsland *g = group_arr[g_index];
/* the range of verts this group uses in 'verts_arr' (not uncluding the last index) */
@@ -1551,7 +1593,7 @@ bool BM_face_split_edgenet_connect_islands(
}
/* tell the 'next' group it doesn't need to create its own back-link */
- unsigned int g_index_other = verts_group_table[index_other];
+ uint g_index_other = verts_group_table[index_other];
group_arr[g_index_other]->has_prev_edge = true;
}
}
@@ -1567,7 +1609,7 @@ bool BM_face_split_edgenet_connect_islands(
*r_edge_net_new_len = edge_net_new_len;
ok = true;
- for (unsigned int i = 0; i < vert_arr_len; i++) {
+ for (uint i = 0; i < vert_arr_len; i++) {
copy_v3_v3(vert_arr[i]->co, vert_coords_backup[i]);
}
@@ -1600,7 +1642,7 @@ finally:
/* Remove edges which have become doubles since splicing vertices together,
* its less trouble then detecting future-doubles on edge-creation. */
- for (unsigned int i = edge_net_init_len; i < edge_net_new_len; i++) {
+ for (uint i = edge_net_init_len; i < edge_net_new_len; i++) {
while (BM_edge_find_double(edge_net_new[i])) {
BM_edge_kill(bm, edge_net_new[i]);
edge_net_new_len--;
@@ -1616,7 +1658,7 @@ finally:
#endif
- for (unsigned int i = 0; i < edge_arr_len; i++) {
+ for (uint i = 0; i < edge_arr_len; i++) {
BM_elem_flag_disable(edge_arr[i], EDGE_NOT_IN_STACK);
BM_elem_flag_disable(edge_arr[i]->v1, VERT_NOT_IN_STACK);
BM_elem_flag_disable(edge_arr[i]->v2, VERT_NOT_IN_STACK);
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
index 72ae7695f0f..bf5cea59e30 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
@@ -32,10 +32,10 @@ bool BM_face_split_edgenet(
bool BM_face_split_edgenet_connect_islands(
BMesh *bm,
- BMFace *f, BMEdge **edge_net_init, const unsigned int edge_net_init_len,
+ BMFace *f, BMEdge **edge_net_init, const uint edge_net_init_len,
bool use_partial_connect,
struct MemArena *arena,
- BMEdge ***r_edge_net_new, unsigned int *r_edge_net_new_len)
+ BMEdge ***r_edge_net_new, uint *r_edge_net_new_len)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 6, 7, 8);
#endif /* __BMESH_POLYGON_EDGENET_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index d8d297c9298..4dcf97e3f35 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -44,13 +44,14 @@
# define BM_CHECK_ELEMENT(el) (void)(el)
#else
int bmesh_elem_check(void *element, const char htype);
-# define BM_CHECK_ELEMENT(el) \
+# define BM_CHECK_ELEMENT(el) { \
if (bmesh_elem_check(el, ((BMHeader *)el)->htype)) { \
printf("check_element failure, with code %i on line %i in file\n" \
" \"%s\"\n\n", \
bmesh_elem_check(el, ((BMHeader *)el)->htype), \
__LINE__, __FILE__); \
- } (void)0
+ } \
+} ((void)0)
#endif
int bmesh_radial_length(const BMLoop *l);
@@ -73,7 +74,7 @@ enum {
};
#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 &= (unsigned char)~(f)); } (void)0
+#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= (uchar)~(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_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index 7ca5640578a..5bdc3927e16 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -36,7 +36,7 @@
#include "BLI_math.h"
#include "BLI_alloca.h"
#include "BLI_linklist.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BKE_customdata.h"
@@ -754,6 +754,22 @@ bool BM_vert_is_edge_pair(const BMVert *v)
}
/**
+ * Fast alternative to ``(BM_vert_edge_count(v) == 2)``
+ * that checks both edges connect to the same faces.
+ */
+bool BM_vert_is_edge_pair_manifold(const BMVert *v)
+{
+ const BMEdge *e = v->e;
+ if (e) {
+ BMEdge *e_other = BM_DISK_EDGE_NEXT(e, v);
+ if (((e_other != e) && (BM_DISK_EDGE_NEXT(e_other, v) == e))) {
+ return BM_edge_is_manifold(e) && BM_edge_is_manifold(e_other);
+ }
+ }
+ return false;
+}
+
+/**
* Access a verts 2 connected edges.
*
* \return true when only 2 verts are found.
@@ -1511,20 +1527,68 @@ float BM_loop_calc_face_angle(const BMLoop *l)
* Calculate the normal at this loop corner or fallback to the face normal on straight lines.
*
* \param l The loop to calculate the normal at
+ * \param epsilon: Value to avoid numeric errors (1e-5f works well).
* \param r_normal Resulting normal
*/
-void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
+float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
{
- if (normal_tri_v3(r_normal,
- l->prev->v->co,
- l->v->co,
- l->next->v->co) != 0.0f)
- {
- /* pass */
+ /* Note: we cannot use result of normal_tri_v3 here to detect colinear vectors (vertex on a straight line)
+ * from zero value, because it does not normalize both vectors before making crossproduct.
+ * Instead of adding two costly normalize computations, just check ourselves for colinear case. */
+ /* Note: FEPSILON might need some finer tweaking at some point? Seems to be working OK for now though. */
+ float v1[3], v2[3], v_tmp[3];
+ sub_v3_v3v3(v1, l->prev->v->co, l->v->co);
+ sub_v3_v3v3(v2, l->next->v->co, l->v->co);
+
+ const float fac =
+ ((v2[0] == 0.0f) ?
+ ((v2[1] == 0.0f) ?
+ ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) : v1[1] / v2[1]) : v1[0] / v2[0]);
+
+ mul_v3_v3fl(v_tmp, v2, fac);
+ sub_v3_v3(v_tmp, v1);
+ if (fac != 0.0f && !is_zero_v3(v1) && len_squared_v3(v_tmp) > epsilon_sq) {
+ /* Not co-linear, we can compute crossproduct and normalize it into normal. */
+ cross_v3_v3v3(r_normal, v1, v2);
+ return normalize_v3(r_normal);
}
else {
copy_v3_v3(r_normal, l->f->no);
+ return 0.0f;
+ }
+}
+
+/**
+ * #BM_loop_calc_face_normal_safe_ex with pre-defined sane epsilon.
+ *
+ * Since this doesn't scale baed on triangle size, fixed value works well.
+ */
+float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
+{
+ return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal);
+}
+
+/**
+ * \brief BM_loop_calc_face_normal
+ *
+ * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
+ *
+ * \param l The loop to calculate the normal at
+ * \param r_normal Resulting normal
+ * \return The length of the cross product (double the area).
+ */
+float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
+{
+ float v1[3], v2[3];
+ sub_v3_v3v3(v1, l->prev->v->co, l->v->co);
+ sub_v3_v3v3(v2, l->next->v->co, l->v->co);
+
+ cross_v3_v3v3(r_normal, v1, v2);
+ const float len = normalize_v3(r_normal);
+ if (UNLIKELY(len == 0.0f)) {
+ copy_v3_v3(r_normal, l->f->no);
}
+ return len;
}
/**
@@ -2326,7 +2390,7 @@ static void bm_mesh_calc_volume_face(const BMFace *f, float *r_vol)
{
const int tottri = f->len - 2;
BMLoop **loops = BLI_array_alloca(loops, f->len);
- unsigned int (*index)[3] = BLI_array_alloca(index, tottri);
+ uint (*index)[3] = BLI_array_alloca(index, tottri);
int j;
BM_face_calc_tessellation(f, false, loops, index);
@@ -2395,8 +2459,8 @@ int BM_mesh_calc_face_groups(
int group_curr = 0;
- unsigned int tot_faces = 0;
- unsigned int tot_touch = 0;
+ uint tot_faces = 0;
+ uint tot_touch = 0;
BMFace **stack;
STACK_DECLARE(stack);
@@ -2553,8 +2617,8 @@ int BM_mesh_calc_edge_groups(
int group_curr = 0;
- unsigned int tot_edges = 0;
- unsigned int tot_touch = 0;
+ uint tot_edges = 0;
+ uint tot_touch = 0;
BMEdge **stack;
STACK_DECLARE(stack);
diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h
index 903fdc59cb8..c9fce96c798 100644
--- a/source/blender/bmesh/intern/bmesh_queries.h
+++ b/source/blender/bmesh/intern/bmesh_queries.h
@@ -85,6 +85,7 @@ int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_vert_is_edge_pair_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b);
bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -113,7 +114,9 @@ BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq
BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq);
float BM_loop_calc_face_angle(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
+float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
+float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
+float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3]) ATTR_NONNULL();
void BM_loop_calc_face_direction(const BMLoop *l, float r_normal[3]);
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);
diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c
index d5afb39d7b7..2ae87b64286 100644
--- a/source/blender/bmesh/operators/bmo_bevel.c
+++ b/source/blender/bmesh/operators/bmo_bevel.c
@@ -66,5 +66,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, clamp_overlap, NULL, -1, material, loop_slide);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
+ BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG);
+ BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "verts.out", BM_VERT, BM_ELEM_TAG);
}
}
diff --git a/source/blender/bmesh/operators/bmo_bisect_plane.c b/source/blender/bmesh/operators/bmo_bisect_plane.c
index bed1ea5cb94..ed232e81b82 100644
--- a/source/blender/bmesh/operators/bmo_bisect_plane.c
+++ b/source/blender/bmesh/operators/bmo_bisect_plane.c
@@ -29,7 +29,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BLI_math.h"
#include "bmesh.h"
@@ -38,7 +38,8 @@
#include "intern/bmesh_operators_private.h" /* own include */
#define ELE_NEW 1
-#define ELE_INPUT 2
+#define ELE_CUT 2
+#define ELE_INPUT 4
void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op)
{
@@ -69,7 +70,7 @@ void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op)
BM_mesh_bisect_plane(bm, plane, use_snap_center, true,
- ELE_NEW, dist);
+ ELE_CUT, ELE_NEW, dist);
if (clear_outer || clear_inner) {
@@ -108,5 +109,5 @@ void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op)
}
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_NEW | ELE_INPUT);
- BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_cut.out", BM_VERT | BM_EDGE, ELE_NEW);
+ BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_cut.out", BM_VERT | BM_EDGE, ELE_CUT);
}
diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c
index 5c9cd8dc3fa..0b5f1bb9ca1 100644
--- a/source/blender/bmesh/operators/bmo_connect.c
+++ b/source/blender/bmesh/operators/bmo_connect.c
@@ -27,7 +27,7 @@
*/
#include "BLI_utildefines.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BLI_alloca.h"
#include "BLI_linklist_stack.h"
@@ -55,7 +55,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera
BMLoop *l_tag_prev = NULL, *l_tag_first = NULL;
BMLoop *l_iter, *l_first;
- unsigned int i;
+ uint i;
STACK_INIT(loops_split, pair_split_max);
STACK_INIT(verts_pair, pair_split_max);
diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
index b8acc9d09b8..67590fe8ef9 100644
--- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c
+++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
@@ -67,8 +67,8 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r
{
BMLoop *l_iter, *l_first;
BMLoop **l_arr = BLI_array_alloca(l_arr, f->len);
- const unsigned int f_len = f->len;
- unsigned int i_a, i_b;
+ const uint f_len = f->len;
+ uint i_a, i_b;
bool found = false;
/* angle finding */
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index a73c86fd122..b474ad9fc7b 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -530,8 +530,8 @@ static void bm_vert_pair_to_matrix(BMVert *v_pair[2], float r_unit_mat[3][3])
float basis_nor_b[3];
/* align normal to direction */
- project_plane_v3_v3v3(basis_nor_a, v_pair[0]->no, basis_dir);
- project_plane_v3_v3v3(basis_nor_b, v_pair[1]->no, basis_dir);
+ project_plane_normalized_v3_v3v3(basis_nor_a, v_pair[0]->no, basis_dir);
+ project_plane_normalized_v3_v3v3(basis_nor_b, v_pair[1]->no, basis_dir);
/* don't normalize before combining so as normals approach the direction, they have less effect (T46784). */
@@ -569,7 +569,7 @@ static void bm_vert_pair_to_matrix(BMVert *v_pair[2], float r_unit_mat[3][3])
float angle_cos_test;
/* project basis dir onto the normal to find its closest angle */
- project_plane_v3_v3v3(basis_dir_proj, basis_dir, l->f->no);
+ project_plane_normalized_v3_v3v3(basis_dir_proj, basis_dir, l->f->no);
if (normalize_v3(basis_dir_proj) > eps) {
angle_cos_test = dot_v3v3(basis_dir_proj, basis_dir);
@@ -586,7 +586,7 @@ static void bm_vert_pair_to_matrix(BMVert *v_pair[2], float r_unit_mat[3][3])
* note: we could add the directions,
* but this more often gives 45d rotated matrix, so just use the best one. */
copy_v3_v3(basis_nor, axis_pair[axis_pair[0].angle_cos < axis_pair[1].angle_cos].nor);
- project_plane_v3_v3v3(basis_nor, basis_nor, basis_dir);
+ project_plane_normalized_v3_v3v3(basis_nor, basis_nor, basis_dir);
cross_v3_v3v3(basis_tmp, basis_dir, basis_nor);
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
index 7b8cb36ab59..fa08d009d40 100644
--- a/source/blender/bmesh/operators/bmo_create.c
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -74,13 +74,13 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
BMVert *verts[2];
BMEdge *e;
- BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)verts, 2);
-
- /* create edge */
- e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE);
- 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);
+ if (BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)verts, 2) == 2) {
+ /* create edge */
+ e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE);
+ 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;
}
@@ -283,14 +283,18 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
*/
if (totv > 2) {
/* TODO, some of these vertes may be connected by edges,
- * this connectivity could be used rather then treating
+ * this connectivity could be used rather than treating
* them as a bunch of isolated verts. */
BMVert **vert_arr = MEM_mallocN(sizeof(BMVert *) * totv, __func__);
BMFace *f;
- BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)vert_arr, totv);
- f = BM_face_create_ngon_vcloud(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE);
+ totv = BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)vert_arr, totv);
+
+ BM_verts_sort_radial_plane(vert_arr, totv);
+
+ /* create edges and find the winding (if faces are attached to any existing edges) */
+ f = BM_face_create_ngon_verts(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE, true, true);
if (f) {
BMO_face_flag_enable(bm, f, ELE_OUT);
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 6e3a8a1473d..2df8e73c2b8 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -309,7 +309,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) {
BMFace *f_pair[2];
if (BM_edge_face_pair(e, &f_pair[0], &f_pair[1])) {
- unsigned int j;
+ uint j;
for (j = 0; j < 2; j++) {
BMLoop *l_first, *l_iter;
l_iter = l_first = BM_FACE_FIRST_LOOP(f_pair[j]);
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
index 56639a097b6..e35c1f3b66c 100644
--- a/source/blender/bmesh/operators/bmo_dupe.c
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -83,7 +83,7 @@ static BMEdge *bmo_edge_copy(
{
BMEdge *e_dst;
BMVert *e_dst_v1, *e_dst_v2;
- unsigned int rlen;
+ uint rlen;
/* see if any of the neighboring faces are
* not being duplicated. in that case,
@@ -378,6 +378,10 @@ void BMO_dupe_from_flag(BMesh *bm, int htype, const char hflag)
* BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
* BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
* BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
+ *
+ * \note Lower level uses of this operator may want to use #BM_mesh_separate_faces
+ * Since it's faster for the 'use_only_faces' case.
+ *
*/
void bmo_split_exec(BMesh *bm, BMOperator *op)
{
diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c
index 233ed746ed4..dcf2570dff4 100644
--- a/source/blender/bmesh/operators/bmo_fill_attribute.c
+++ b/source/blender/bmesh/operators/bmo_fill_attribute.c
@@ -91,7 +91,7 @@ static void bm_face_copy_shared_all(
/**
* Flood fill attributes.
*/
-static unsigned int bmesh_face_attribute_fill(
+static uint bmesh_face_attribute_fill(
BMesh *bm,
const bool use_normals, const bool use_data)
{
@@ -102,7 +102,7 @@ static unsigned int bmesh_face_attribute_fill(
BMIter iter;
BMLoop *l;
- unsigned int face_tot = 0;
+ uint face_tot = 0;
BLI_LINKSTACK_INIT(loop_queue_prev);
diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c
index 04ae915b707..dc4ebf50754 100644
--- a/source/blender/bmesh/operators/bmo_fill_grid.c
+++ b/source/blender/bmesh/operators/bmo_fill_grid.c
@@ -187,15 +187,15 @@ static void bm_loop_interp_from_grid_boundary_2(BMesh *bm, BMLoop *l, BMLoop *l_
* Avoids calling #barycentric_weights_v2_quad often by caching weights into an array.
*/
static void barycentric_weights_v2_grid_cache(
- const unsigned int xtot, const unsigned int ytot,
+ const uint xtot, const uint ytot,
float (*weight_table)[4])
{
float x_step = 1.0f / (float)(xtot - 1);
float y_step = 1.0f / (float)(ytot - 1);
- unsigned int i = 0;
+ uint i = 0;
float xy_fl[2];
- unsigned int x, y;
+ uint x, y;
for (y = 0; y < ytot; y++) {
xy_fl[1] = y_step * (float)y;
for (x = 0; x < xtot; x++) {
@@ -219,13 +219,13 @@ static void barycentric_weights_v2_grid_cache(
* \param v_grid 2d array of verts, all boundary verts must be set, we fill in the middle.
*/
static void bm_grid_fill_array(
- BMesh *bm, BMVert **v_grid, const unsigned int xtot, unsigned const int ytot,
+ BMesh *bm, BMVert **v_grid, const uint xtot, unsigned const int ytot,
const short mat_nr, const bool use_smooth,
const bool use_flip, const bool use_interp_simple)
{
const bool use_vert_interp = CustomData_has_interp(&bm->vdata);
const bool use_loop_interp = CustomData_has_interp(&bm->ldata);
- unsigned int x, y;
+ uint x, y;
/* for use_loop_interp */
BMLoop *((*larr_x_a)[2]), *((*larr_x_b)[2]), *((*larr_y_a)[2]), *((*larr_y_b)[2]);
@@ -393,7 +393,7 @@ static void bm_grid_fill_array(
BMLoop *l_quad[4];
BMLoop *l_bound[4];
BMLoop *l_tmp;
- unsigned int x_side, y_side, i;
+ uint x_side, y_side, i;
char interp_from;
@@ -496,12 +496,12 @@ static void bm_grid_fill(
{
#define USE_FLIP_DETECT
- const unsigned int xtot = (unsigned int)BM_edgeloop_length_get(estore_a);
- const unsigned int ytot = (unsigned int)BM_edgeloop_length_get(estore_rail_a);
+ const uint xtot = (uint)BM_edgeloop_length_get(estore_a);
+ const uint ytot = (uint)BM_edgeloop_length_get(estore_rail_a);
//BMVert *v;
- unsigned int i;
+ uint i;
#ifdef DEBUG
- unsigned int x, y;
+ uint x, y;
#endif
LinkData *el;
bool use_flip = false;
diff --git a/source/blender/bmesh/operators/bmo_fill_holes.c b/source/blender/bmesh/operators/bmo_fill_holes.c
index eadfbdb1aa8..869994a98b9 100644
--- a/source/blender/bmesh/operators/bmo_fill_holes.c
+++ b/source/blender/bmesh/operators/bmo_fill_holes.c
@@ -36,7 +36,7 @@
void bmo_holes_fill_exec(BMesh *bm, BMOperator *op)
{
BMOperator op_attr;
- const unsigned int sides = BMO_slot_int_get(op->slots_in, "sides");
+ const uint sides = BMO_slot_int_get(op->slots_in, "sides");
BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index c52c608e671..a64c6d74a93 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -275,7 +275,7 @@ static void bmo_face_inset_individual(
BMLoop *l_iter, *l_first;
BMLoop *l_other;
- unsigned int i;
+ uint i;
float e_length_prev;
l_first = BM_FACE_FIRST_LOOP(f);
@@ -647,6 +647,10 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
} (void)0
#define VERT_ORIG_GET(_v) \
(const float *)BLI_ghash_lookup_default(vert_coords, (_v), (_v)->co)
+ /* memory for the coords isn't given back to the arena,
+ * acceptable in this case since it runs a fixed number of times. */
+#define VERT_ORIG_REMOVE(_v) \
+ BLI_ghash_remove(vert_coords, (_v), NULL, NULL)
for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
@@ -659,7 +663,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
/* run the separate arg */
if (!BM_edge_is_boundary(es->e_old)) {
- bmesh_edge_separate(bm, es->e_old, es->l, false);
+ bmesh_kernel_edge_separate(bm, es->e_old, es->l, false);
}
/* calc edge-split info */
@@ -738,7 +742,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
/* disable touching twice, this _will_ happen if the flags not disabled */
BM_elem_flag_disable(v, BM_ELEM_TAG);
- bmesh_vert_separate(bm, v, &vout, &r_vout_len, false);
+ bmesh_kernel_vert_separate(bm, v, &vout, &r_vout_len, false);
v = NULL; /* don't use again */
/* in some cases the edge doesn't split off */
@@ -972,7 +976,11 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
v_glue = v_split;
}
else {
- BM_vert_splice(bm, v_glue, v_split);
+ if (BM_vert_splice(bm, v_glue, v_split)) {
+ if (use_vert_coords_orig) {
+ VERT_ORIG_REMOVE(v_split);
+ }
+ }
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index 655fb346976..69198ff35ab 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -132,11 +132,11 @@ struct DelimitData_CD {
};
struct DelimitData {
- unsigned int do_seam : 1;
- unsigned int do_sharp : 1;
- unsigned int do_mat : 1;
- unsigned int do_angle_face : 1;
- unsigned int do_angle_shape : 1;
+ uint do_seam : 1;
+ uint do_sharp : 1;
+ uint do_mat : 1;
+ uint do_angle_face : 1;
+ uint do_angle_shape : 1;
float angle_face;
float angle_face__cos;
@@ -272,7 +272,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
/* data: edge-to-join, sort_value: error weight */
struct SortPointerByFloat *jedges;
unsigned i, totedge;
- unsigned int totedge_tag = 0;
+ uint totedge_tag = 0;
struct DelimitData delimit_data = {0};
diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
index 7a6f779b34f..269f933f27f 100644
--- a/source/blender/bmesh/operators/bmo_offset_edgeloops.c
+++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
@@ -33,7 +33,7 @@
#include "BLI_math.h"
#include "BLI_alloca.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BKE_customdata.h"
@@ -270,7 +270,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
v_other = BM_edge_other_vert(e, v);
if (BM_elem_index_get(v_other) == -1) {
if (BM_vert_is_edge_pair(v_other)) {
- /* defer bmesh_jekv to avoid looping over data we're removing */
+ /* defer bmesh_kernel_join_edge_kill_vert to avoid looping over data we're removing */
v_other->e = e;
STACK_PUSH(varr, v_other);
}
@@ -278,7 +278,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
}
while ((v = STACK_POP(varr))) {
- bmesh_jekv(bm, v->e, v, true, false, false);
+ bmesh_kernel_join_edge_kill_vert(bm, v->e, v, true, false, false);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index 8408169d85e..95d61763902 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -760,11 +760,13 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
BMOpSlot *slot_verts_out = BMO_slot_get(op->slots_out, "verts.out");
const float dia = BMO_slot_float_get(op->slots_in, "size");
- const unsigned int xtot = max_ii(2, BMO_slot_int_get(op->slots_in, "x_segments"));
- const unsigned int ytot = max_ii(2, BMO_slot_int_get(op->slots_in, "y_segments"));
+ const uint xtot = max_ii(2, BMO_slot_int_get(op->slots_in, "x_segments"));
+ const uint ytot = max_ii(2, BMO_slot_int_get(op->slots_in, "y_segments"));
const float xtot_inv2 = 2.0f / (xtot - 1);
const float ytot_inv2 = 2.0f / (ytot - 1);
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMVert **varr;
BMVert *vquad[4];
@@ -772,7 +774,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
float mat[4][4];
float vec[3], tvec[3];
- unsigned int x, y, i;
+ uint x, y, i;
BMO_slot_mat4_get(op->slots_in, "matrix", mat);
@@ -814,7 +816,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
#undef XY
if (calc_uvs) {
- BM_mesh_calc_uvs_grid(bm, xtot, ytot, FACE_MARK);
+ BM_mesh_calc_uvs_grid(bm, xtot, ytot, FACE_MARK, cd_loop_uv_offset);
}
}
@@ -826,7 +828,9 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
* \param y_segments The y-resolution of the grid
* \param oflag The flag to check faces with.
*/
-void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsigned int y_segments, const short oflag)
+void BM_mesh_calc_uvs_grid(
+ BMesh *bm, const uint x_segments, const uint y_segments,
+ const short oflag, const int cd_loop_uv_offset)
{
BMFace *f;
BMLoop *l;
@@ -835,9 +839,7 @@ void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsig
const float dx = 1.0f / (float)(x_segments - 1);
const float dy = 1.0f / (float)(y_segments - 1);
float x = 0.0f;
- float y = 0.0f;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float y = dy;
int loop_index;
@@ -852,16 +854,16 @@ void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsig
switch (loop_index) {
case 0:
- x += dx;
+ y -= dy;
break;
case 1:
- y += dy;
+ x += dx;
break;
case 2:
- x -= dx;
+ y += dy;
break;
case 3:
- y -= dy;
+ x -= dx;
break;
default:
break;
@@ -884,7 +886,9 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
const float dia = BMO_slot_float_get(op->slots_in, "diameter");
const int seg = BMO_slot_int_get(op->slots_in, "u_segments");
const int tot = BMO_slot_int_get(op->slots_in, "v_segments");
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMOperator bmop, prevop;
BMVert *eve, *preveve;
@@ -982,7 +986,7 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
}
}
- BM_mesh_calc_uvs_sphere(bm, FACE_MARK);
+ BM_mesh_calc_uvs_sphere(bm, FACE_MARK, cd_loop_uv_offset);
}
/* and now do imat */
@@ -1000,7 +1004,9 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
const float dia = BMO_slot_float_get(op->slots_in, "diameter");
const float dia_div = dia / 200.0f;
const int subdiv = BMO_slot_int_get(op->slots_in, "subdivisions");
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMVert *eva[12];
BMVert *v;
@@ -1026,7 +1032,6 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
}
int uvi = 0;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
for (a = 0; a < 20; a++) {
BMFace *f;
BMVert *v1, *v2, *v3;
@@ -1122,7 +1127,7 @@ static void bm_mesh_calc_uvs_sphere_face(BMFace *f, const int cd_loop_uv_offset)
}
/* Shift borderline coordinates to the left. */
- if (fabsf(theta - M_PI) < 0.0001f) {
+ if (fabsf(theta - (float)M_PI) < 0.0001f) {
theta = -M_PI;
}
@@ -1157,13 +1162,13 @@ static void bm_mesh_calc_uvs_sphere_face(BMFace *f, const int cd_loop_uv_offset)
* \param bm The BMesh to operate on
* \param oflag The flag to check faces with.
*/
-void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag)
+void BM_mesh_calc_uvs_sphere(
+ BMesh *bm,
+ const short oflag, const int cd_loop_uv_offset)
{
BMFace *f;
BMIter iter;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
@@ -1206,7 +1211,9 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
int i;
BMO_slot_mat4_get(op->slots_in, "matrix", mat);
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
for (i = 0; i < monkeynv; i++) {
float v[3];
@@ -1234,7 +1241,6 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
}
int uvi = 0;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
for (i = 0; i < monkeynf; i++) {
BMFace *f_new_a = BM_face_create_quad_tri(bm,
tv[monkeyf[i][0] + i - monkeyo],
@@ -1279,11 +1285,13 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
{
- const float dia = BMO_slot_float_get(op->slots_in, "diameter");
+ const float radius = BMO_slot_float_get(op->slots_in, "radius");
const int segs = BMO_slot_int_get(op->slots_in, "segments");
const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends");
const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris");
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMVert *v1, *lastv1 = NULL, *cent1, *firstv1 = NULL;
float vec[3], mat[4][4], phi, phid;
@@ -1307,8 +1315,8 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
for (a = 0; a < segs; a++, phi += phid) {
/* Going this way ends up with normal(s) upward */
- vec[0] = -dia * sinf(phi);
- vec[1] = dia * cosf(phi);
+ vec[0] = -radius * sinf(phi);
+ vec[1] = radius * cosf(phi);
vec[2] = 0.0f;
mul_m4_v3(mat, vec);
v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
@@ -1343,7 +1351,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
BMO_face_flag_enable(bm, f, FACE_NEW);
if (calc_uvs) {
- BM_mesh_calc_uvs_circle(bm, mat, dia, FACE_NEW);
+ BM_mesh_calc_uvs_circle(bm, mat, radius, FACE_NEW, cd_loop_uv_offset);
}
}
@@ -1362,14 +1370,14 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
* \param radius The size of the circle.
* \param oflag The flag to check faces with.
*/
-void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, const short oflag)
+void BM_mesh_calc_uvs_circle(
+ BMesh *bm, float mat[4][4], const float radius,
+ const short oflag, const int cd_loop_uv_offset)
{
BMFace *f;
BMLoop *l;
BMIter fiter, liter;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
const float uv_scale = 0.5f / radius;
const float uv_center = 0.5f;
@@ -1409,7 +1417,9 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
int segs = BMO_slot_int_get(op->slots_in, "segments");
const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends");
const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris");
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
int a;
if (!segs)
@@ -1506,7 +1516,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
}
if (calc_uvs) {
- BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK);
+ BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK, cd_loop_uv_offset);
}
if (!cap_tris) {
@@ -1530,12 +1540,12 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
*/
void BM_mesh_calc_uvs_cone(
BMesh *bm, float mat[4][4],
- const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, const short oflag)
+ const float radius_top, const float radius_bottom, const int segments, const bool cap_ends,
+ const short oflag, const int cd_loop_uv_offset)
{
BMFace *f;
BMLoop *l;
BMIter fiter, liter;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
const float uv_width = 1.0f / (float)segments;
const float uv_height = cap_ends ? 0.5f : 1.0f;
@@ -1566,7 +1576,7 @@ void BM_mesh_calc_uvs_cone(
BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for ensuring the mesh has UVs */
- x = 0.0f;
+ x = 1.0f;
y = 1.0f - uv_height;
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
@@ -1580,7 +1590,7 @@ void BM_mesh_calc_uvs_cone(
switch (loop_index) {
case 0:
- x += uv_width;
+ /* Continue in the last position */
break;
case 1:
y += uv_height;
@@ -1598,8 +1608,6 @@ void BM_mesh_calc_uvs_cone(
luv->uv[0] = x;
luv->uv[1] = y;
}
-
- x += uv_width;
}
else {
/* top or bottom face - so unwrap it by transforming back to a circle and using the X/Y coords */
@@ -1629,8 +1637,10 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
BMVert *verts[8];
float mat[4][4];
float off = BMO_slot_float_get(op->slots_in, "size") / 2.0f;
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
- int i, x, y, z;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
/* rotation order set to match 'BM_mesh_calc_uvs_cube' */
const char faces[6][4] = {
{0, 1, 3, 2},
@@ -1644,11 +1654,11 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
BMO_slot_mat4_get(op->slots_in, "matrix", mat);
if (!off) off = 0.5f;
- i = 0;
+ int i = 0;
- for (x = -1; x < 2; x += 2) {
- for (y = -1; y < 2; y += 2) {
- for (z = -1; z < 2; z += 2) {
+ for (int x = -1; x < 2; x += 2) {
+ for (int y = -1; y < 2; y += 2) {
+ for (int z = -1; z < 2; z += 2) {
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);
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index 0ad8247e539..e85751531ae 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -30,7 +30,8 @@
#include "BLI_math.h"
#include "BLI_alloca.h"
-#include "BLI_stackdefines.h"
+#include "BLI_kdtree.h"
+#include "BLI_utildefines_stack.h"
#include "BLI_stack.h"
#include "BKE_customdata.h"
@@ -153,7 +154,7 @@ static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_target
finally:
{
- unsigned int i;
+ uint i;
for (i = 0; i < STACK_SIZE(verts); i++) {
BMO_vert_flag_disable(bm, verts[i], VERT_IN_FACE);
}
@@ -165,7 +166,7 @@ finally:
BLI_assert(f_new != f);
if (f_new) {
- unsigned int i = 0;
+ uint i = 0;
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
do {
@@ -277,22 +278,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
BMO_mesh_delete_oflag_context(bm, ELE_DEL, DEL_ONLYTAGGED);
}
-static int vergaverco(const void *e1, const void *e2)
-{
- const BMVert *v1 = *(const void **)e1, *v2 = *(const void **)e2;
- float x1 = v1->co[0] + v1->co[1] + v1->co[2];
- float x2 = v2->co[0] + v2->co[1] + v2->co[2];
-
- if (x1 > x2) return 1;
- else if (x1 < x2) return -1;
- else return 0;
-}
-
-// #define VERT_TESTED 1 // UNUSED
-#define VERT_DOUBLE 2
-#define VERT_TARGET 4
#define VERT_KEEP 8
-// #define VERT_MARK 16 // UNUSED
#define VERT_IN 32
#define EDGE_MARK 1
@@ -440,20 +426,24 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op)
edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- float min[3], max[3], center[3];
+ float center[3];
+ int count = 0;
BMVert *v_tar;
+ zero_v3(center);
+
if (!BMO_edge_flag_test(bm, e, EDGE_MARK))
continue;
BLI_assert(BLI_stack_is_empty(edge_stack));
- INIT_MINMAX(min, max);
for (e = BMW_begin(&walker, e->v1); e; e = BMW_step(&walker)) {
BLI_stack_push(edge_stack, &e);
- minmax_v3v3_v3(min, max, e->v1->co);
- minmax_v3v3_v3(min, max, e->v2->co);
+ add_v3_v3(center, e->v1->co);
+ add_v3_v3(center, e->v2->co);
+
+ count += 2;
/* prevent adding to slot_targetmap multiple times */
BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
@@ -461,15 +451,14 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op)
}
if (!BLI_stack_is_empty(edge_stack)) {
-
- mid_v3_v3v3(center, min, max);
+ mul_v3_fl(center, 1.0f / count);
/* snap edges to a point. for initial testing purposes anyway */
e = *(BMEdge **)BLI_stack_peek(edge_stack);
v_tar = e->v1;
while (!BLI_stack_is_empty(edge_stack)) {
- unsigned int j;
+ uint j;
BLI_stack_pop(edge_stack, &e);
for (j = 0; j < 2; j++) {
@@ -581,77 +570,62 @@ static void bmesh_find_doubles_common(
BMesh *bm, BMOperator *op,
BMOperator *optarget, BMOpSlot *optarget_slot)
{
- BMVert **verts;
- int verts_len;
+ const BMOpSlot *slot_verts = BMO_slot_get(op->slots_in, "verts");
+ BMVert * const *verts = (BMVert **)slot_verts->data.buf;
+ const int verts_len = slot_verts->len;
- int i, j, keepvert = 0;
+ bool has_keep_vert = false;
+ bool found_duplicates = false;
const float dist = BMO_slot_float_get(op->slots_in, "dist");
- const float dist_sq = dist * dist;
- const float dist3 = ((float)M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */
/* Test whether keep_verts arg exists and is non-empty */
if (BMO_slot_exists(op->slots_in, "keep_verts")) {
BMOIter oiter;
- keepvert = BMO_iter_new(&oiter, op->slots_in, "keep_verts", BM_VERT) != NULL;
+ has_keep_vert = BMO_iter_new(&oiter, op->slots_in, "keep_verts", BM_VERT) != NULL;
}
- /* get the verts as an array we can sort */
- verts = BMO_slot_as_arrayN(op->slots_in, "verts", &verts_len);
-
- /* sort by vertex coordinates added together */
- qsort(verts, verts_len, sizeof(BMVert *), vergaverco);
-
/* Flag keep_verts */
- if (keepvert) {
+ if (has_keep_vert) {
BMO_slot_buffer_flag_enable(bm, op->slots_in, "keep_verts", BM_VERT, VERT_KEEP);
}
- for (i = 0; i < verts_len; i++) {
- BMVert *v_check = verts[i];
-
- if (BMO_vert_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) {
- continue;
+ int *duplicates = MEM_mallocN(sizeof(int) * verts_len, __func__);
+ {
+ KDTree *tree = BLI_kdtree_new(verts_len);
+ for (int i = 0; i < verts_len; i++) {
+ BLI_kdtree_insert(tree, i, verts[i]->co);
+ if (has_keep_vert && BMO_vert_flag_test(bm, verts[i], VERT_KEEP)) {
+ duplicates[i] = i;
+ }
+ else {
+ duplicates[i] = -1;
+ }
}
- for (j = i + 1; j < verts_len; j++) {
- BMVert *v_other = verts[j];
-
- /* a match has already been found, (we could check which is best, for now don't) */
- if (BMO_vert_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) {
- continue;
- }
+ BLI_kdtree_balance(tree);
+ found_duplicates = BLI_kdtree_calc_duplicates_fast(tree, dist, false, duplicates) != 0;
+ BLI_kdtree_free(tree);
+ }
- /* Compare sort values of the verts using 3x tolerance (allowing for the tolerance
- * on each of the three axes). This avoids the more expensive length comparison
- * for most vertex pairs. */
- if ((v_other->co[0] + v_other->co[1] + v_other->co[2]) -
- (v_check->co[0] + v_check->co[1] + v_check->co[2]) > dist3)
- {
- break;
+ if (found_duplicates) {
+ for (int i = 0; i < verts_len; i++) {
+ BMVert *v_check = verts[i];
+ if (duplicates[i] == -1) {
+ /* nop (others can use as target) */
}
-
- if (keepvert) {
- if (BMO_vert_flag_test(bm, v_other, VERT_KEEP) == BMO_vert_flag_test(bm, v_check, VERT_KEEP))
- continue;
+ else if (duplicates[i] == i) {
+ /* keep (others can use as target) */
}
-
- 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_vert_flag_test(bm, v_other, VERT_KEEP)) {
- SWAP(BMVert *, v_check, v_other);
- }
-
- 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);
+ else {
+ BMVert *v_other = verts[duplicates[i]];
+ BLI_assert(ELEM(duplicates[duplicates[i]], -1, duplicates[i]));
+ BMO_slot_map_elem_insert(optarget, optarget_slot, v_check, v_other);
}
}
}
- MEM_freeN(verts);
+ MEM_freeN(duplicates);
}
void bmo_remove_doubles_exec(BMesh *bm, BMOperator *op)
diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c
index 1a83bafc074..2a7b85ac8fd 100644
--- a/source/blender/bmesh/operators/bmo_smooth_laplacian.c
+++ b/source/blender/bmesh/operators/bmo_smooth_laplacian.c
@@ -172,7 +172,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
float w1, w2, w3, w4;
int i, j;
bool has_4_vert;
- unsigned int idv1, idv2, idv3, idv4, idv[4];
+ uint idv1, idv2, idv3, idv4, idv[4];
BMEdge *e;
BMFace *f;
BMIter eiter;
@@ -289,7 +289,7 @@ static void fill_laplacian_matrix(LaplacianSystem *sys)
float w2, w3, w4;
int i, j;
bool has_4_vert;
- unsigned int idv1, idv2, idv3, idv4, idv[4];
+ uint idv1, idv2, idv3, idv4, idv[4];
BMEdge *e;
BMFace *f;
@@ -420,7 +420,7 @@ static void validate_solution(LaplacianSystem *sys, int usex, int usey, int usez
float leni, lene;
float vini, vend;
float *vi1, *vi2, ve1[3], ve2[3];
- unsigned int idv1, idv2;
+ uint idv1, idv2;
BMOIter siter;
BMVert *v;
BMEdge *e;
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index ce031e1c230..adcc0c71629 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -40,7 +40,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BLI_alloca.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -66,7 +66,7 @@
/* Specialized Utility Funcs */
#ifndef NDEBUG
-static unsigned int bm_verts_tag_count(BMesh *bm)
+static uint bm_verts_tag_count(BMesh *bm)
{
int count = 0;
BMIter iter;
@@ -390,9 +390,9 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3])
* Tag faces connected to an edge loop as FACE_SHARED
* if all vertices are VERT_SHARED.
*/
-static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const unsigned int e_arr_len)
+static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const uint e_arr_len)
{
- unsigned int i;
+ uint i;
for (i = 0; i < e_arr_len; i++) {
BMEdge *e = e_arr[i];
@@ -412,9 +412,9 @@ static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const unsigned i
/**
* Un-Tag faces connected to an edge loop, clearing FACE_SHARED
*/
-static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const unsigned int e_arr_len_iter)
+static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const uint e_arr_len_iter)
{
- unsigned int i;
+ uint i;
for (i = 0; i < e_arr_len_iter; i++) {
BMEdge *e = e_arr_iter[i];
@@ -454,16 +454,16 @@ static LoopPairStore *bm_edgering_pair_store_create(
LoopPairStore *lpair = MEM_mallocN(sizeof(*lpair), __func__);
if (interp_mode == SUBD_RING_INTERP_SURF) {
- const unsigned int len_a = BM_edgeloop_length_get(el_store_a);
- const unsigned int len_b = BM_edgeloop_length_get(el_store_b);
- const unsigned int e_arr_a_len = len_a - (BM_edgeloop_is_closed(el_store_a) ? 0 : 1);
- const unsigned int e_arr_b_len = len_b - (BM_edgeloop_is_closed(el_store_b) ? 0 : 1);
+ const uint len_a = BM_edgeloop_length_get(el_store_a);
+ const uint len_b = BM_edgeloop_length_get(el_store_b);
+ const uint e_arr_a_len = len_a - (BM_edgeloop_is_closed(el_store_a) ? 0 : 1);
+ const uint e_arr_b_len = len_b - (BM_edgeloop_is_closed(el_store_b) ? 0 : 1);
BMEdge **e_arr_a = BLI_array_alloca(e_arr_a, e_arr_a_len);
BMEdge **e_arr_b = BLI_array_alloca(e_arr_b, e_arr_b_len);
- unsigned int i;
+ uint i;
struct BMEdgeLoopStore *el_store_pair[2] = {el_store_a, el_store_b};
- unsigned int side_index;
+ uint side_index;
float (*nors_pair[2])[3];
GHash *nors_gh_pair[2];
@@ -768,8 +768,8 @@ static void bm_edgering_pair_interpolate(
bm_vert_calc_surface_tangent(bm, v_b, no_b);
#else
{
- const unsigned int index_a = GET_UINT_FROM_POINTER(BLI_ghash_lookup(lpair->nors_gh_a, v_a));
- const unsigned int index_b = GET_UINT_FROM_POINTER(BLI_ghash_lookup(lpair->nors_gh_b, v_b));
+ const uint index_a = GET_UINT_FROM_POINTER(BLI_ghash_lookup(lpair->nors_gh_a, v_a));
+ const uint index_b = GET_UINT_FROM_POINTER(BLI_ghash_lookup(lpair->nors_gh_b, v_b));
BLI_assert(BLI_ghash_haskey(lpair->nors_gh_a, v_a));
BLI_assert(BLI_ghash_haskey(lpair->nors_gh_b, v_b));
diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c
index 6bd3174d27a..4e8bace59e0 100644
--- a/source/blender/bmesh/operators/bmo_triangulate.c
+++ b/source/blender/bmesh/operators/bmo_triangulate.c
@@ -77,7 +77,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
GHash *sf_vert_map;
float normal[3];
const int scanfill_flag = BLI_SCANFILL_CALC_HOLES | BLI_SCANFILL_CALC_POLYS | BLI_SCANFILL_CALC_LOOSE;
- unsigned int nors_tot;
+ uint nors_tot;
bool calc_winding = false;
sf_vert_map = BLI_ghash_ptr_new_ex(__func__, BMO_slot_buffer_count(op->slots_in, "edges"));
@@ -89,7 +89,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
ScanFillVert *sf_verts[2];
BMVert **e_verts = &e->v1;
- unsigned int i;
+ uint i;
BMO_edge_flag_enable(bm, e, EDGE_MARK);
@@ -115,7 +115,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
* Since we don't know winding, just accumulate */
ScanFillVert *sf_vert;
struct SortNormal *nors;
- unsigned int i;
+ uint i;
bool is_degenerate = true;
nors = MEM_mallocN(sizeof(*nors) * nors_tot, __func__);
@@ -124,7 +124,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
BMVert *v = sf_vert->tmp.p;
BMIter eiter;
BMEdge *e_pair[2];
- unsigned int e_index = 0;
+ uint e_index = 0;
nors[i].value = -1.0f;
@@ -199,7 +199,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
int winding_votes = 0;
for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
BMVert *v_tri[3] = {sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p};
- unsigned int i, i_prev;
+ uint i, i_prev;
for (i = 0, i_prev = 2; i < 3; i_prev = i++) {
e = BM_edge_exists(v_tri[i], v_tri[i_prev]);
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index 3e3a6547b75..6e6242fc9f9 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -62,7 +62,7 @@ typedef struct EdRotState {
#if 0
/* use BLI_ghashutil_inthash_v4 direct */
-static unsigned int erot_gsetutil_hash(const void *ptr)
+static uint erot_gsetutil_hash(const void *ptr)
{
const EdRotState *e_state = (const EdRotState *)ptr;
return BLI_ghashutil_inthash_v4(&e_state->v1);
@@ -150,7 +150,7 @@ static float bm_edge_calc_rotate_beauty__area(
(ELEM(v4, v1, v2, v3) == false));
add_v3_v3v3(no, no_a, no_b);
- if (UNLIKELY((no_scale = normalize_v3(no)) <= FLT_EPSILON)) {
+ if (UNLIKELY((no_scale = normalize_v3(no)) == 0.0f)) {
break;
}
@@ -182,7 +182,12 @@ static float bm_edge_calc_rotate_beauty__area(
}
}
- return BLI_polyfill_beautify_quad_rotate_calc(v1_xy, v2_xy, v3_xy, v4_xy);
+ /**
+ * Important to lock degenerate here,
+ * since the triangle pars will be projected into different 2D spaces.
+ * Allowing to rotate out of a degenerate state can flip the faces (when performed iteratively).
+ */
+ return BLI_polyfill_beautify_quad_rotate_calc_ex(v1_xy, v2_xy, v3_xy, v4_xy, true);
} while (false);
return FLT_MAX;
@@ -368,7 +373,7 @@ void BM_mesh_beautify_fill(
TIMEIT_START(beautify_fill);
#endif
- eheap = BLI_heap_new_ex((unsigned int)edge_array_len);
+ eheap = BLI_heap_new_ex((uint)edge_array_len);
eheap_table = MEM_mallocN(sizeof(HeapNode *) * (size_t)edge_array_len, __func__);
/* build heap */
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 6c168bd9114..51a0fa4b2cc 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -57,6 +57,7 @@
#define BEVEL_EPSILON_ANG DEG2RADF(2.0f)
#define BEVEL_SMALL_ANG DEG2RADF(10.0f)
#define BEVEL_MAX_ADJUST_PCT 10.0f
+#define BEVEL_MAX_AUTO_ADJUST_PCT 300.0f
/* happens far too often, uncomment for development */
// #define BEVEL_ASSERT_PROJECT
@@ -204,6 +205,38 @@ static int bev_debug_flags = 0;
#define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2)
#define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4)
+/* this flag values will get set on geom we want to return in 'out' slots for edges and verts */
+#define EDGE_OUT 4
+#define VERT_OUT 8
+
+/* If we're called from the modifier, tool flags aren't available, but don't need output geometry */
+static void flag_out_edge(BMesh *bm, BMEdge *bme)
+{
+ if (bm->use_toolflags)
+ BMO_edge_flag_enable(bm, bme, EDGE_OUT);
+}
+
+static void flag_out_vert(BMesh *bm, BMVert *bmv)
+{
+ if (bm->use_toolflags)
+ BMO_vert_flag_enable(bm, bmv, VERT_OUT);
+}
+
+static void disable_flag_out_edge(BMesh *bm, BMEdge *bme)
+{
+ if (bm->use_toolflags)
+ BMO_edge_flag_disable(bm, bme, EDGE_OUT);
+}
+
+/* Are d1 and d2 parallel or nearly so? */
+static bool nearly_parallel(const float d1[3], const float d2[3])
+{
+ float ang;
+
+ ang = angle_v3v3(d1, d2);
+ return (fabsf(ang) < BEVEL_EPSILON_ANG) || (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG);
+}
+
/* Make a new BoundVert of the given kind, insert it at the end of the circular linked
* list with entry point bv->boundstart, and return it. */
static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float co[3])
@@ -252,6 +285,7 @@ static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert
NewVert *nv = mesh_vert(vm, i, j, k);
nv->v = BM_vert_create(bm, nv->co, eg, BM_CREATE_NOP);
BM_elem_flag_disable(nv->v, BM_ELEM_TAG);
+ flag_out_vert(bm, nv->v);
}
static void copy_mesh_vert(
@@ -323,15 +357,33 @@ static bool edge_half_offset_changed(EdgeHalf *e)
e->offset_r != e->offset_r_spec;
}
-static bool any_edge_half_offset_changed(BevVert *bv)
+static float adjusted_rel_change(float val, float spec)
+{
+ float relchg;
+
+ relchg = 0.0f;
+ if (val != spec) {
+ if (spec == 0)
+ relchg = 1000.0f; /* arbitrary large value */
+ else
+ relchg = fabsf((val - spec) / spec);
+ }
+ return relchg;
+}
+
+static float max_edge_half_offset_rel_change(BevVert *bv)
{
int i;
+ float max_rel_change;
+ EdgeHalf *e;
+ max_rel_change = 0.0f;
for (i = 0; i < bv->edgecount; i++) {
- if (edge_half_offset_changed(&bv->edges[i]))
- return true;
+ e = &bv->edges[i];
+ max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_l, e->offset_l_spec));
+ max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_r, e->offset_r_spec));
}
- return false;
+ return max_rel_change;
}
/* Return the next EdgeHalf after from_e that is beveled.
@@ -476,9 +528,12 @@ static BMFace *bev_create_ngon(
}
/* not essential for bevels own internal logic,
- * this is done so the operator can select newly created faces */
+ * this is done so the operator can select newly created geometry */
if (f) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
+ BM_ITER_ELEM(bme, &iter, f, BM_EDGES_OF_FACE) {
+ flag_out_edge(bm, bme);
+ }
}
if (mat_nr >= 0)
@@ -897,8 +952,12 @@ static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetc
return false;
}
cross_v3_v3v3(fno, dir1, dir2);
- if (dot_v3v3(fno, v->no) < 0.0f)
+ if (dot_v3v3(fno, v->no) < 0.0f) {
ang = 2.0f * (float)M_PI - ang; /* angle is reflex */
+ if (r_angle)
+ *r_angle = ang;
+ return false;
+ }
if (r_angle)
*r_angle = ang;
@@ -1036,7 +1095,7 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
{
EdgeHalf *e;
Profile *pro;
- float co1[3], co2[3], co3[3], d1[3], d2[3], l;
+ float co1[3], co2[3], co3[3], d1[3], d2[3];
bool do_linear_interp;
copy_v3_v3(co1, bndv->nv.co);
@@ -1074,8 +1133,8 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
normalize_v3(d1);
normalize_v3(d2);
cross_v3_v3v3(pro->plane_no, d1, d2);
- l = normalize_v3(pro->plane_no);
- if (l <= BEVEL_EPSILON_BIG) {
+ normalize_v3(pro->plane_no);
+ if (nearly_parallel(d1, d2)) {
/* co1 - midco -co2 are collinear.
* Should be case that beveled edge is coplanar with two boundary verts.
* We want to move the profile to that common plane, if possible.
@@ -1107,17 +1166,24 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co);
normalize_v3(d3);
normalize_v3(d4);
- add_v3_v3v3(co3, co1, d3);
- add_v3_v3v3(co4, co2, d4);
- isect_kind = isect_line_line_v3(co1, co3, co2, co4, meetco, isect2);
- if (isect_kind != 0) {
- copy_v3_v3(pro->midco, meetco);
- }
- else {
+ if (nearly_parallel(d3, d4)) {
/* offset lines are collinear - want linear interpolation */
mid_v3_v3v3(pro->midco, co1, co2);
do_linear_interp = true;
}
+ else {
+ add_v3_v3v3(co3, co1, d3);
+ add_v3_v3v3(co4, co2, d4);
+ isect_kind = isect_line_line_v3(co1, co3, co2, co4, meetco, isect2);
+ if (isect_kind != 0) {
+ copy_v3_v3(pro->midco, meetco);
+ }
+ else {
+ /* offset lines don't intersect - want linear interpolation */
+ mid_v3_v3v3(pro->midco, co1, co2);
+ do_linear_interp = true;
+ }
+ }
}
}
copy_v3_v3(pro->cob, co2);
@@ -1126,8 +1192,8 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
sub_v3_v3v3(d2, pro->midco, co2);
normalize_v3(d2);
cross_v3_v3v3(pro->plane_no, d1, d2);
- l = normalize_v3(pro->plane_no);
- if (l <= BEVEL_EPSILON_BIG) {
+ normalize_v3(pro->plane_no);
+ if (nearly_parallel(d1, d2)) {
/* whole profile is collinear with edge: just interpolate */
do_linear_interp = true;
}
@@ -1951,6 +2017,7 @@ static void adjust_offsets(BevelParams *bp)
GHashIterator giter;
EdgeHalf *e, *efirst, *eother;
GSQueue *q;
+ float max_rel_adj;
BLI_assert(!bp->vertex_only);
GHASH_ITER(giter, bp->vert_hash) {
@@ -1966,7 +2033,7 @@ static void adjust_offsets(BevelParams *bp)
searchi = -1;
GHASH_ITER(giter, bp->vert_hash) {
bv = BLI_ghashIterator_getValue(&giter);
- if (!bv->visited && any_edge_half_offset_changed(bv)) {
+ if (!bv->visited && max_edge_half_offset_rel_change(bv) > 0.0f) {
i = BM_elem_index_get(bv->v);
if (!searchbv || i < searchi) {
searchbv = bv;
@@ -1996,6 +2063,24 @@ static void adjust_offsets(BevelParams *bp)
}
}
BLI_gsqueue_free(q);
+
+ /* Should we auto-limit the error accumulation? Typically, spirals can lead to 100x relative adjustments,
+ * and somewhat hacky mechanism of using bp->limit_offset to indicate "clamp the adjustments" is not
+ * obvious to users, who almost certainaly want clamping in this situation.
+ * The reason not to clamp always is that some models work better without it (e.g., Bent_test in regression
+ * suite, where relative adjust maximum is about .6). */
+ if (!bp->limit_offset) {
+ max_rel_adj = 0.0f;
+ GHASH_ITER(giter, bp->vert_hash) {
+ bv = BLI_ghashIterator_getValue(&giter);
+ max_rel_adj = max_ff(max_rel_adj, max_edge_half_offset_rel_change(bv));
+ }
+ if (max_rel_adj > BEVEL_MAX_AUTO_ADJUST_PCT / 100.0f) {
+ bp->limit_offset = true;
+ adjust_offsets(bp);
+ bp->limit_offset = false;
+ }
+ }
}
/* Do the edges at bv form a "pipe"?
@@ -2257,7 +2342,7 @@ static int interp_range(const float *frac, int n, const float f, float *r_rest)
/* Interpolate given vmesh to make one with target nseg border vertices on the profiles */
static VMesh *interp_vmesh(BevelParams *bp, VMesh *vm0, int nseg)
{
- int n, ns0, nseg2, odd, i, j, k, j0, k0, k0prev;
+ int n, ns0, nseg2, odd, i, j, k, j0, k0, k0prev, j0inc, k0inc;
float *prev_frac, *frac, *new_frac, *prev_new_frac;
float f, restj, restk, restkprev;
float quad[4][3], co[3], center[3];
@@ -2301,10 +2386,12 @@ static VMesh *interp_vmesh(BevelParams *bp, VMesh *vm0, int nseg)
copy_v3_v3(co, mesh_vert_canon(vm0, i, j0, k0)->co);
}
else {
+ j0inc = (restj < BEVEL_EPSILON || j0 == ns0) ? 0 : 1;
+ k0inc = (restk < BEVEL_EPSILON || k0 == ns0) ? 0 : 1;
copy_v3_v3(quad[0], mesh_vert_canon(vm0, i, j0, k0)->co);
- copy_v3_v3(quad[1], mesh_vert_canon(vm0, i, j0, k0 + 1)->co);
- copy_v3_v3(quad[2], mesh_vert_canon(vm0, i, j0 + 1, k0 + 1)->co);
- copy_v3_v3(quad[3], mesh_vert_canon(vm0, i, j0 + 1, k0)->co);
+ copy_v3_v3(quad[1], mesh_vert_canon(vm0, i, j0, k0 + k0inc)->co);
+ copy_v3_v3(quad[2], mesh_vert_canon(vm0, i, j0 + j0inc, k0 + k0inc)->co);
+ copy_v3_v3(quad[3], mesh_vert_canon(vm0, i, j0 + j0inc, k0)->co);
interp_bilinear_quad_v3(quad, restk, restj, co);
}
copy_v3_v3(mesh_vert(vm1, i, j, k)->co, co);
@@ -3153,6 +3240,7 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
BMFace *f_new;
BLI_assert(v_fan == l_fan->v);
f_new = BM_face_split(bm, f, l_fan, l_fan->next->next, &l_new, NULL, false);
+ flag_out_edge(bm, l_new->e);
if (f_new->len > f->len) {
f = f_new;
@@ -3199,6 +3287,7 @@ static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv)
else {
BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false);
f = l_new->f;
+ flag_out_edge(bm, l_new->e);
/* walk around the new face to get the next verts to split */
l_a = l_new->prev;
@@ -3218,7 +3307,7 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
{
VMesh *vm = bv->vmesh;
BMVert *v1, *v2;
- BMEdge *e_eg;
+ BMEdge *e_eg, *bme;
Profile *pro;
float co[3];
BoundVert *bndv;
@@ -3260,7 +3349,9 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
v1 = mesh_vert(vm, 0, 0, k)->v;
v2 = mesh_vert(vm, 0, 0, k + 1)->v;
BLI_assert(v1 != NULL && v2 != NULL);
- BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE);
+ bme = BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE);
+ if (bme)
+ flag_out_edge(bm, bme);
}
}
}
@@ -3557,7 +3648,7 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme)
{
BMEdge *bme, *bme2;
BMIter iter;
- BMFace *f;
+ BMFace *f, *bestf;
EdgeHalf *e;
EdgeHalf *e2;
BMLoop *l;
@@ -3595,10 +3686,21 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme)
bme = e->e;
bme2 = e2->e;
BLI_assert(bme != NULL);
+ if (e->fnext != NULL || e2->fprev != NULL)
+ continue;
+ /* Which faces have successive loops that are for bme and bme2?
+ * There could be more than one. E.g., in manifold ntot==2 case.
+ * Prefer one that has loop in same direction as e. */
+ bestf = NULL;
BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
f = l->f;
- if ((l->prev->e == bme2 || l->next->e == bme2) && !e->fnext && !e2->fprev)
- e->fnext = e2->fprev = f;
+ if ((l->prev->e == bme2 || l->next->e == bme2)) {
+ if (!bestf || l->v == bv->v)
+ bestf = f;
+ }
+ if (bestf) {
+ e->fnext = e2->fprev = bestf;
+ }
}
}
}
@@ -3830,7 +3932,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
/* Face f has at least one beveled vertex. Rebuild f */
static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
{
- BMIter liter;
+ BMIter liter, eiter, fiter;
BMLoop *l, *lprev;
BevVert *bv;
BoundVert *v, *vstart, *vend;
@@ -3838,10 +3940,10 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
VMesh *vm;
int i, k, n;
bool do_rebuild = false;
- bool go_ccw, corner3special;
+ bool go_ccw, corner3special, keep;
BMVert *bmv;
BMEdge *bme, *bme_new, *bme_prev;
- BMFace *f_new;
+ BMFace *f_new, *f_other;
BMVert **vv = NULL;
BMVert **vv_fix = NULL;
BMEdge **ee = NULL;
@@ -3979,9 +4081,21 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
}
}
- /* don't select newly created boundary faces... */
+ /* don't select newly or return created boundary faces... */
if (f_new) {
BM_elem_flag_disable(f_new, BM_ELEM_TAG);
+ /* Also don't want new edges that aren't part of a new bevel face */
+ BM_ITER_ELEM(bme, &eiter, f_new, BM_EDGES_OF_FACE) {
+ keep = false;
+ BM_ITER_ELEM(f_other, &fiter, bme, BM_FACES_OF_EDGE) {
+ if (BM_elem_flag_test(f_other, BM_ELEM_TAG)) {
+ keep = true;
+ break;
+ }
+ }
+ if (!keep)
+ disable_flag_out_edge(bm, bme);
+ }
}
}
@@ -4063,8 +4177,9 @@ static void bevel_reattach_wires(BMesh *bm, BevelParams *bp, BMVert *v)
}
}
} while ((bndv = bndv->next) != bv->vmesh->boundstart);
- if (vclosest)
+ if (vclosest) {
BM_edge_create(bm, vclosest, votherclosest, e, BM_CREATE_NO_DOUBLE);
+ }
}
}
@@ -4416,61 +4531,206 @@ static void set_profile_spacing(BevelParams *bp)
}
/*
- * Calculate and return an offset that is the lesser of the current
+ * Assume we have a situation like:
+ *
+ * a d
+ * \ /
+ * A \ / C
+ * \ th1 th2/
+ * b---------c
+ * B
+ *
+ * where edges are A, B, and C,
+ * following a face around vertices a, b, c, d;
+ * th1 is angle abc and th2 is angle bcd;
+ * and the argument EdgeHalf eb is B, going from b to c.
+ * In general case, edge offset specs for A, B, C have
+ * the form ka*t, kb*t, kc*t where ka, kb, kc are some factors
+ * (may be 0) and t is the current bp->offset.
+ * We want to calculate t at which the clone of B parallel
+ * to it collapses. This can be calculated using trig.
+ * Another case of geometry collision that can happen is
+ * When B slides along A because A is unbeveled.
+ * Then it might collide with a. Similarly for B sliding along C.
+ */
+static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb)
+{
+ EdgeHalf *ea, *ec, *ebother;
+ BevVert *bvc;
+ BMLoop *lb;
+ BMVert *va, *vb, *vc, *vd;
+ float ka, kb, kc, g, h, t, den, no_collide_offset, th1, th2, sin1, sin2, tan1, tan2, limit;
+
+ limit = no_collide_offset = bp->offset + 1e6;
+ if (bp->offset == 0.0f)
+ return no_collide_offset;
+ kb = eb->offset_l_spec;
+ ea = eb->next; /* note: this is in direction b --> a */
+ ka = ea->offset_r_spec;
+ if (eb->is_rev) {
+ vc = eb->e->v1;
+ vb = eb->e->v2;
+ }
+ else {
+ vb = eb->e->v1;
+ vc = eb->e->v2;
+ }
+ va = ea->is_rev ? ea->e->v1 : ea->e->v2;
+ bvc = NULL;
+ ebother = find_other_end_edge_half(bp, eb, &bvc);
+ if (ebother != NULL) {
+ ec = ebother->prev; /* note: this is in direction c --> d*/
+ vc = bvc->v;
+ kc = ec->offset_l_spec;
+ vd = ec->is_rev ? ec->e->v1 : ec->e->v2;
+ }
+ else {
+ /* No bevvert for w, so C can't be beveled */
+ kc = 0.0f;
+ ec = NULL;
+ /* Find an edge from c that has same face */
+ lb = BM_face_edge_share_loop(eb->fnext, eb->e);
+ if (!lb) {
+ return no_collide_offset;
+ }
+ if (lb->next->v == vc)
+ vd = lb->next->next->v;
+ else if (lb->v == vc)
+ vd = lb->prev->v;
+ else {
+ return no_collide_offset;
+ }
+ }
+ if (ea->e == eb->e || (ec && ec->e == eb->e))
+ return no_collide_offset;
+ ka = ka / bp->offset;
+ kb = kb / bp->offset;
+ kc = kc / bp->offset;
+ th1 = angle_v3v3v3(va->co, vb->co, vc->co);
+ th2 = angle_v3v3v3(vb->co, vc->co, vd->co);
+
+ /* First calculate offset at which edge B collapses, which happens
+ * when advancing clones of A, B, C all meet at a point.
+ * This only happens if at least two of those three edges have non-zero k's */
+ sin1 = sinf(th1);
+ sin2 = sinf(th2);
+ if ((ka > 0.0f) + (kb > 0.0f) + (kc > 0.0f) >= 2) {
+ tan1 = tanf(th1);
+ tan2 = tanf(th2);
+ g = tan1 * tan2;
+ h = sin1 * sin2;
+ den = g * (ka * sin2 + kc * sin1) + kb * h * (tan1 + tan2);
+ if (den != 0.0f) {
+ t = BM_edge_calc_length(eb->e);
+ t *= g * h / den;
+ if (t >= 0.0f)
+ limit = t;
+ }
+ }
+
+ /* Now check edge slide cases */
+ if (kb > 0.0f && ka == 0.0f /*&& bvb->selcount == 1 && bvb->edgecount > 2*/) {
+ t = BM_edge_calc_length(ea->e);
+ t *= sin1 / kb;
+ if (t >= 0.0f && t < limit)
+ limit = t;
+ }
+ if (kb > 0.0f && kc == 0.0f /* && bvc && ec && bvc->selcount == 1 && bvc->edgecount > 2 */) {
+ t = BM_edge_calc_length(ec->e);
+ t *= sin2 / kb;
+ if (t >= 0.0f && t < limit)
+ limit = t;
+ }
+ return limit;
+}
+
+/*
+ * We have an edge A between vertices a and b,
+ * where EdgeHalf ea is the half of A that starts at a.
+ * For vertex-only bevels, the new vertices slide from a at a rate ka*t
+ * and from b at a rate kb*t.
+ * We want to calculate the t at which the two meet.
+ */
+static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea)
+{
+ float limit, ka, kb, no_collide_offset, la, kab;
+ EdgeHalf *eb;
+
+ limit = no_collide_offset = bp->offset + 1e6;
+ if (bp->offset == 0.0f)
+ return no_collide_offset;
+ ka = ea->offset_l_spec / bp->offset;
+ eb = find_other_end_edge_half(bp, ea, NULL);
+ kb = eb ? eb->offset_l_spec / bp->offset : 0.0f;
+ kab = ka + kb;
+ la = BM_edge_calc_length(ea->e);
+ if (kab <= 0.0f)
+ return no_collide_offset;
+ limit = la / kab;
+ return limit;
+}
+
+/*
+ * Calculate an offset that is the lesser of the current
* bp.offset and the maximum possible offset before geometry
* collisions happen.
- * Currently this is a quick and dirty estimate of the max
- * possible: half the minimum edge length of any vertex involved
- * in a bevel. This is usually conservative.
- * The correct calculation is quite complicated.
- * TODO: implement this correctly.
+ * If the offset changes as a result of this, adjust the
+ * current edge offset specs to reflect this clamping,
+ * and store the new offset in bp.offset.
*/
-static float bevel_limit_offset(BMesh *bm, BevelParams *bp)
+static void bevel_limit_offset(BevelParams *bp)
{
- BMVert *v;
- BMEdge *e;
- BMIter v_iter, e_iter;
- float limited_offset, half_elen;
- bool vbeveled;
+ BevVert *bv;
+ EdgeHalf *eh;
+ GHashIterator giter;
+ float limited_offset, offset_factor, collision_offset;
+ int i;
limited_offset = bp->offset;
- if (bp->offset_type == BEVEL_AMT_PERCENT) {
- if (limited_offset > 50.0f)
- limited_offset = 50.0f;
- return limited_offset;
- }
- BM_ITER_MESH (v, &v_iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ GHASH_ITER(giter, bp->vert_hash) {
+ bv = BLI_ghashIterator_getValue(&giter);
+ for (i = 0; i < bv->edgecount; i++) {
+ eh = &bv->edges[i];
if (bp->vertex_only) {
- vbeveled = true;
+ collision_offset = vertex_collide_offset(bp, eh);
+ if (collision_offset < limited_offset)
+ limited_offset = collision_offset;
}
else {
- vbeveled = false;
- BM_ITER_ELEM (e, &e_iter, v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG)) {
- vbeveled = true;
- break;
- }
- }
+ collision_offset = geometry_collide_offset(bp, eh);
+ if (collision_offset < limited_offset)
+ limited_offset = collision_offset;
}
- if (vbeveled) {
- BM_ITER_ELEM (e, &e_iter, v, BM_EDGES_OF_VERT) {
- half_elen = 0.5f * BM_edge_calc_length(e);
- if (half_elen < limited_offset)
- limited_offset = half_elen;
- }
+ }
+ }
+
+ if (limited_offset < bp->offset) {
+ /* All current offset specs have some number times bp->offset,
+ * so we can just multiply them all by the reduction factor
+ * of the offset to have the effect of recalculating the specs
+ * with the new limited_offset.
+ */
+ offset_factor = limited_offset / bp->offset;
+ GHASH_ITER(giter, bp->vert_hash) {
+ bv = BLI_ghashIterator_getValue(&giter);
+ for (i = 0; i < bv->edgecount; i++) {
+ eh = &bv->edges[i];
+ eh->offset_l_spec *= offset_factor;
+ eh->offset_r_spec *= offset_factor;
+ eh->offset_l *= offset_factor;
+ eh->offset_r *= offset_factor;
}
}
+ bp->offset = limited_offset;
}
- return limited_offset;
}
/**
* - Currently only bevels BM_ELEM_TAG'd verts and edges.
*
- * - Newly created faces are BM_ELEM_TAG'd too,
- * the caller needs to ensure this is cleared before calling
- * if its going to use this face tag.
+ * - Newly created faces, edges, and verts are BM_ELEM_TAG'd too,
+ * the caller needs to ensure these are cleared before calling
+ * if its going to use this tag.
*
* - If limit_offset is set, adjusts offset down if necessary
* to avoid geometry collisions.
@@ -4489,6 +4749,7 @@ void BM_mesh_bevel(
BMEdge *e;
BevVert *bv;
BevelParams bp = {NULL};
+ GHashIterator giter;
bp.offset = offset;
bp.offset_type = offset_type;
@@ -4512,24 +4773,33 @@ void BM_mesh_bevel(
BLI_memarena_use_calloc(bp.mem_arena);
set_profile_spacing(&bp);
- if (limit_offset)
- bp.offset = bevel_limit_offset(bm, &bp);
-
/* Analyze input vertices, sorting edges and assigning initial new vertex positions */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
bv = bevel_vert_construct(bm, &bp, v);
- if (bv)
+ if (!limit_offset && bv)
build_boundary(&bp, bv, true);
}
}
+ /* Perhaps clamp offset to avoid geometry colliisions */
+ if (limit_offset) {
+ bevel_limit_offset(&bp);
+
+ /* Assign initial new vertex positions */
+ GHASH_ITER(giter, bp.vert_hash) {
+ bv = BLI_ghashIterator_getValue(&giter);
+ build_boundary(&bp, bv, true);
+ }
+ }
+
/* Perhaps do a pass to try to even out widths */
if (!bp.vertex_only) {
adjust_offsets(&bp);
}
/* Build the meshes around vertices, now that positions are final */
+ /* Note: could use GHASH_ITER over bp.vert_hash when backward compatibility no longer matters */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
bv = find_bevvert(&bp, v);
@@ -4562,6 +4832,20 @@ void BM_mesh_bevel(
}
}
+ /* When called from operator (as opposed to modifier), bm->use_toolflags
+ * will be set, and we to transfer the oflags to BM_ELEM_TAGs */
+ if (bm->use_toolflags) {
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BMO_vert_flag_test(bm, v, VERT_OUT))
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ }
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BMO_edge_flag_test(bm, e, EDGE_OUT)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ }
+ }
+
/* primary free */
BLI_ghash_free(bp.vert_hash, NULL, NULL);
BLI_memarena_free(bp.mem_arena);
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index 51b92a3c45e..f3927a3ff67 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -38,7 +38,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BLI_alloca.h"
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
@@ -74,7 +74,7 @@ static short plane_point_test_v3(const float plane[4], const float co[3], const
#define BM_VERT_DIST(v) ((v)->no[0]) /* Distance from the plane. */
#define BM_VERT_SORTVAL(v) ((v)->no[1]) /* Temp value for sorting. */
#define BM_VERT_LOOPINDEX(v) /* The verts index within a face (temp var) */ \
- (*((unsigned int *)(&(v)->no[2])))
+ (*((uint *)(&(v)->no[2])))
/**
* Hide flag access
@@ -110,10 +110,10 @@ static int bm_vert_sortval_cb(const void *v_a_v, const void *v_b_v)
}
-static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], const short oflag_center)
+static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], const short oflag_center, const short oflag_new)
{
/* unlikely more than 2 verts are needed */
- const unsigned int f_len_orig = (unsigned int)f->len;
+ const uint f_len_orig = (uint)f->len;
BMVert **vert_split_arr = BLI_array_alloca(vert_split_arr, f_len_orig);
STACK_DECLARE(vert_split_arr);
BMLoop *l_iter, *l_first;
@@ -154,10 +154,11 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
/* common case, just cut the face once */
BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true);
if (l_new) {
- if (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);
+ if (oflag_center | oflag_new) {
+ BMO_edge_flag_enable(bm, l_new->e, oflag_center | oflag_new);
+ }
+ if (oflag_new) {
+ BMO_face_flag_enable(bm, l_new->f, oflag_new);
}
}
}
@@ -170,7 +171,7 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
STACK_DECLARE(face_split_arr);
float sort_dir[3];
- unsigned int i;
+ uint i;
/* ---- */
@@ -245,7 +246,7 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
if (is_inside) {
BMLoop *l_a, *l_b;
bool found = false;
- unsigned int j;
+ uint j;
for (j = 0; j < STACK_SIZE(face_split_arr); j++) {
/* would be nice to avoid loop lookup here,
@@ -269,10 +270,11 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
f_tmp = BM_face_split(bm, face_split_arr[j], l_a, l_b, &l_new, NULL, true);
if (l_new) {
- if (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);
+ if (oflag_center | oflag_new) {
+ BMO_edge_flag_enable(bm, l_new->e, oflag_center | oflag_new);
+ }
+ if (oflag_new) {
+ BMO_face_flag_enable(bm, l_new->f, oflag_new);
}
}
@@ -307,10 +309,10 @@ finally:
void BM_mesh_bisect_plane(
BMesh *bm, const float plane[4],
const bool use_snap_center, const bool use_tag,
- const short oflag_center, const float eps)
+ const short oflag_center, const short oflag_new, const float eps)
{
- unsigned int einput_len;
- unsigned int i;
+ uint einput_len;
+ uint i;
BMEdge **edges_arr = MEM_mallocN(sizeof(*edges_arr) * (size_t)bm->totedge, __func__);
BLI_LINKSTACK_DECLARE(face_stack, BMFace *);
@@ -343,7 +345,7 @@ void BM_mesh_bisect_plane(
}
else {
BMEdge *e;
- einput_len = (unsigned int)bm->totedge;
+ einput_len = (uint)bm->totedge;
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
edge_is_cut_enable(e);
edges_arr[i] = e;
@@ -390,7 +392,7 @@ void BM_mesh_bisect_plane(
const float dist[2] = {BM_VERT_DIST(e->v1), BM_VERT_DIST(e->v2)};
if (side[0] && side[1] && (side[0] != side[1])) {
- const float e_fac = fabsf(dist[0]) / fabsf(dist[0] - dist[1]);
+ const float e_fac = dist[0] / (dist[0] - dist[1]);
BMVert *v_new;
if (e->l) {
@@ -404,10 +406,17 @@ void BM_mesh_bisect_plane(
} while ((l_iter = l_iter->radial_next) != l_first);
}
- v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac);
+ {
+ BMEdge *e_new;
+ v_new = BM_edge_split(bm, e, e->v1, &e_new, e_fac);
+ if (oflag_new) {
+ BMO_edge_flag_enable(bm, e_new, oflag_new);
+ }
+ }
+
vert_is_center_enable(v_new);
- if (oflag_center) {
- BMO_vert_flag_enable(bm, v_new, oflag_center);
+ if (oflag_new | oflag_center) {
+ BMO_vert_flag_enable(bm, v_new, oflag_new | oflag_center);
}
BM_VERT_DIR(v_new) = 0;
@@ -416,7 +425,7 @@ void BM_mesh_bisect_plane(
else if (side[0] == 0 || side[1] == 0) {
/* check if either edge verts are aligned,
* if so - tag and push all faces that use it into the stack */
- unsigned int j;
+ uint j;
BM_ITER_ELEM_INDEX (v, &iter, e, BM_VERTS_OF_EDGE, j) {
if (side[j] == 0) {
if (vert_is_center_test(v) == 0) {
@@ -448,7 +457,7 @@ void BM_mesh_bisect_plane(
MEM_freeN(edges_arr);
while ((f = BLI_LINKSTACK_POP(face_stack))) {
- bm_face_bisect_verts(bm, f, plane, oflag_center);
+ bm_face_bisect_verts(bm, f, plane, oflag_center, oflag_new);
}
/* now we have all faces to split in the stack */
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.h b/source/blender/bmesh/tools/bmesh_bisect_plane.h
index 7f3a97c4c79..fb99a1c8214 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.h
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.h
@@ -30,6 +30,6 @@
void BM_mesh_bisect_plane(
BMesh *bm, const float plane[4],
const bool use_snap_center, const bool use_tag,
- const short oflag_center, const float eps);
+ const short oflag_center, const short oflag_new, const float eps);
#endif /* __BMESH_BISECT_PLANE_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 372d341f223..36ae7231f94 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -40,7 +40,7 @@
#include "BLI_edgehash.h"
#include "BLI_polyfill2d.h"
#include "BLI_polyfill2d_beautify.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BKE_customdata.h"
@@ -180,7 +180,7 @@ static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_
{
BMIter liter;
BMLoop *l;
- unsigned int i;
+ uint i;
for (i = 0; i < 2; i++) {
/* loop over both verts */
@@ -367,7 +367,7 @@ static void bm_decim_build_edge_cost(
{
BMIter iter;
BMEdge *e;
- unsigned int i;
+ uint i;
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
eheap_table[i] = NULL; /* keep sanity check happy */
@@ -418,12 +418,12 @@ static bool bm_edge_symmetry_check_cb(void *user_data, int index, const float UN
return false;
}
-static int *bm_edge_symmetry_map(BMesh *bm, unsigned int symmetry_axis, float limit)
+static int *bm_edge_symmetry_map(BMesh *bm, uint symmetry_axis, float limit)
{
struct KD_Symmetry_Data sym_data;
BMIter iter;
BMEdge *e, **etable;
- unsigned int i;
+ uint i;
int *edge_symmetry_map;
const float limit_sq = SQUARE(limit);
KDTree *tree;
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index 92300ae66a2..f0ac6c673c9 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -43,10 +43,10 @@ static bool bm_vert_dissolve_fan_test(BMVert *v)
BMVert *varr[4];
- unsigned int tot_edge = 0;
- unsigned int tot_edge_boundary = 0;
- unsigned int tot_edge_manifold = 0;
- unsigned int tot_edge_wire = 0;
+ uint tot_edge = 0;
+ uint tot_edge_boundary = 0;
+ uint tot_edge_manifold = 0;
+ uint tot_edge_wire = 0;
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_boundary(e)) {
@@ -97,11 +97,11 @@ static bool bm_vert_dissolve_fan(BMesh *bm, BMVert *v)
BMIter iter;
BMEdge *e;
- unsigned int tot_loop = 0;
- unsigned int tot_edge = 0;
- unsigned int tot_edge_boundary = 0;
- unsigned int tot_edge_manifold = 0;
- unsigned int tot_edge_wire = 0;
+ uint tot_loop = 0;
+ uint tot_edge = 0;
+ uint tot_edge_boundary = 0;
+ uint tot_edge_manifold = 0;
+ uint tot_edge_wire = 0;
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_boundary(e)) {
@@ -143,7 +143,7 @@ static bool bm_vert_dissolve_fan(BMesh *bm, BMVert *v)
if (tot_loop) {
BMLoop *f_loop[4];
- unsigned int i;
+ uint i;
/* ensure there are exactly tot_loop loops */
BLI_assert(BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v, tot_loop) == NULL);
@@ -192,8 +192,8 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool
BMIter iter;
- const unsigned int offset = 0;
- const unsigned int nth = 2;
+ const uint offset = 0;
+ const uint nth = 2;
int iter_step;
@@ -229,8 +229,8 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool
#ifdef USE_WALKER
BMWalker walker;
#else
- unsigned int depth = 1;
- unsigned int i;
+ uint depth = 1;
+ uint i;
#endif
BMVert *v_first = NULL;
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c
index 2a1946df7ae..193a032b46e 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.c
+++ b/source/blender/bmesh/tools/bmesh_edgenet.c
@@ -100,13 +100,13 @@ static BMEdge *bm_edgenet_edge_get_next(
*
* This function returns half a loop, the caller needs to run twice to get both sides.
*/
-static unsigned int bm_edgenet_path_from_pass(
+static uint bm_edgenet_path_from_pass(
BMVert *v, LinkNode **v_ls,
VertNetInfo *vnet_info, BLI_mempool *path_pool)
{
VertNetInfo *vn = &vnet_info[BM_elem_index_get(v)];
const int pass = vn->pass;
- unsigned int v_ls_tot = 0;
+ uint v_ls_tot = 0;
do {
BLI_linklist_prepend_pool(v_ls, v, path_pool);
@@ -127,10 +127,10 @@ static bool bm_edgenet_path_check_overlap(
VertNetInfo *vnet_info)
{
/* vert order doesn't matter */
- unsigned int v_ls_tot = 0;
+ uint v_ls_tot = 0;
LinkNode *v_ls = NULL;
BMVert *v_pair[2] = {v1, v2};
- unsigned int i;
+ uint i;
for (i = 0; i < 2; i++) {
BMVert *v = v_pair[i];
@@ -162,7 +162,7 @@ static bool bm_edgenet_path_check_overlap(
* Create a face from the path.
*/
static BMFace *bm_edgenet_face_from_path(
- BMesh *bm, LinkNode *path, const unsigned int path_len)
+ BMesh *bm, LinkNode *path, const uint path_len)
{
BMFace *f;
LinkNode *v_lnk;
@@ -205,8 +205,8 @@ static BMEdge *bm_edgenet_path_step(
BMEdge *e;
BMIter iter;
- unsigned int tot;
- unsigned int v_ls_tot;
+ uint tot;
+ uint v_ls_tot;
begin:
@@ -277,8 +277,8 @@ begin:
* \return A linked list of verts.
*/
static LinkNode *bm_edgenet_path_calc(
- BMEdge *e, const int pass_nr, const unsigned int path_cost_max,
- unsigned int *r_path_len, unsigned int *r_path_cost,
+ BMEdge *e, const int pass_nr, const uint path_cost_max,
+ uint *r_path_len, uint *r_path_cost,
VertNetInfo *vnet_info, BLI_mempool *path_pool)
{
VertNetInfo *vn_1, *vn_2;
@@ -288,7 +288,7 @@ static LinkNode *bm_edgenet_path_calc(
LinkNode *v_ls_prev = NULL;
LinkNode *v_ls_next = NULL;
- unsigned int path_cost_accum = 0;
+ uint path_cost_accum = 0;
BLI_assert(bm_edge_step_ok(e));
@@ -331,7 +331,7 @@ static LinkNode *bm_edgenet_path_calc(
if (e_found) {
LinkNode *path = NULL;
- unsigned int path_len;
+ uint path_len;
BLI_linklist_free_pool(v_ls_next, NULL, path_pool);
BLI_linklist_free_pool(v_ls_prev, NULL, path_pool);
@@ -376,12 +376,12 @@ static LinkNode *bm_edgenet_path_calc(
* _don't_ have a better option.
*/
static LinkNode *bm_edgenet_path_calc_best(
- BMEdge *e, int *pass_nr, unsigned int path_cost_max,
- unsigned int *r_path_len, unsigned int *r_path_cost,
+ BMEdge *e, int *pass_nr, uint path_cost_max,
+ uint *r_path_len, uint *r_path_cost,
VertNetInfo *vnet_info, BLI_mempool *path_pool)
{
LinkNode *path;
- unsigned int path_cost;
+ uint path_cost;
path = bm_edgenet_path_calc(e, *pass_nr, path_cost_max,
r_path_len, &path_cost,
@@ -399,8 +399,8 @@ static LinkNode *bm_edgenet_path_calc_best(
/* Check every edge to see if any can give a better path.
* This avoids very strange/long paths from being created. */
- const unsigned int path_len = *r_path_len;
- unsigned int i, i_prev;
+ const uint path_len = *r_path_len;
+ uint i, i_prev;
BMVert **vert_arr = BLI_array_alloca(vert_arr, path_len);
LinkNode *v_lnk;
@@ -413,8 +413,8 @@ static LinkNode *bm_edgenet_path_calc_best(
BMEdge *e_other = BM_edge_exists(vert_arr[i], vert_arr[i_prev]);
if (e_other != e) {
LinkNode *path_test;
- unsigned int path_len_test;
- unsigned int path_cost_test;
+ uint path_len_test;
+ uint path_cost_test;
path_test = bm_edgenet_path_calc(e_other, *pass_nr, path_cost,
&path_len_test, &path_cost_test,
@@ -471,8 +471,8 @@ void BM_mesh_edgenet(
while (true) {
LinkNode *path = NULL;
- unsigned int path_len;
- unsigned int path_cost;
+ uint path_len;
+ uint path_cost;
e = bm_edgenet_edge_get_next(bm, &edge_queue, edge_queue_pool);
if (e == NULL) {
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.c b/source/blender/bmesh/tools/bmesh_edgesplit.c
index a59a5c43c82..3a844a0b8d9 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.c
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.c
@@ -96,7 +96,7 @@ void BM_mesh_edgesplit(
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- unsigned int i;
+ uint i;
for (i = 0; i < 2; i++) {
BMVert *v = ((&e->v1)[i]);
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 58234ddf3bd..9d1b20cb4d2 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -44,7 +44,7 @@
#include "BLI_sort_utils.h"
#include "BLI_linklist_stack.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#ifndef NDEBUG
# include "BLI_array_utils.h"
#endif
@@ -152,7 +152,7 @@ struct ISectState {
*/
struct LinkBase {
LinkNode *list;
- unsigned int list_len;
+ uint list_len;
};
static bool ghash_insert_link(
@@ -193,7 +193,7 @@ struct vert_sort_t {
static void edge_verts_sort(const float co[3], struct LinkBase *v_ls_base)
{
/* not optimal but list will be typically < 5 */
- unsigned int i;
+ uint i;
struct vert_sort_t *vert_sort = BLI_array_alloca(vert_sort, v_ls_base->list_len);
LinkNode *node;
@@ -246,8 +246,8 @@ static void face_edges_split(
bool use_island_connect,
MemArena *mem_arena_edgenet)
{
- unsigned int i;
- unsigned int edge_arr_len = e_ls_base->list_len;
+ uint i;
+ uint edge_arr_len = e_ls_base->list_len;
BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len);
LinkNode *node;
BLI_assert(f->head.htype == BM_FACE);
@@ -263,7 +263,7 @@ static void face_edges_split(
#ifdef USE_NET_ISLAND_CONNECT
if (use_island_connect) {
- unsigned int edge_arr_holes_len;
+ uint edge_arr_holes_len;
BMEdge **edge_arr_holes;
if (BM_face_split_edgenet_connect_islands(
bm, f,
@@ -305,14 +305,14 @@ static enum ISectType intersect_line_tri(
const struct ISectEpsilon *e)
{
float p_dir[3];
- unsigned int i_t0;
+ uint i_t0;
float fac;
sub_v3_v3v3(p_dir, p0, p1);
normalize_v3(p_dir);
for (i_t0 = 0; i_t0 < 3; i_t0++) {
- const unsigned int i_t1 = (i_t0 + 1) % 3;
+ const uint i_t1 = (i_t0 + 1) % 3;
float te_dir[3];
sub_v3_v3v3(te_dir, t_cos[i_t0], t_cos[i_t1]);
@@ -375,7 +375,7 @@ static BMVert *bm_isect_edge_tri(
{
BMesh *bm = s->bm;
int k_arr[IX_TOT][4];
- unsigned int i;
+ uint i;
const int ti[3] = {UNPACK3_EX(BM_elem_index_get, t, )};
float ix[3];
@@ -470,7 +470,7 @@ static BMVert *bm_isect_edge_tri(
}
if ((*r_side >= IX_EDGE_TRI_EDGE0) && (*r_side <= IX_EDGE_TRI_EDGE2)) {
- i = (unsigned int)(*r_side - IX_EDGE_TRI_EDGE0);
+ i = (uint)(*r_side - IX_EDGE_TRI_EDGE0);
e = BM_edge_exists(t[i], t[(i + 1) % 3]);
if (e) {
edge_verts_add(s, e, iv, false);
@@ -537,7 +537,7 @@ static void bm_isect_tri_tri(
const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)};
float f_a_nor[3];
float f_b_nor[3];
- unsigned int i;
+ uint i;
/* should be enough but may need to bump */
@@ -578,9 +578,9 @@ static void bm_isect_tri_tri(
/* first check in any verts are touching
* (any case where we wont create new verts)
*/
- unsigned int i_a;
+ uint i_a;
for (i_a = 0; i_a < 3; i_a++) {
- unsigned int i_b;
+ uint 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) {
#ifdef USE_DUMP
@@ -603,12 +603,12 @@ static void bm_isect_tri_tri(
/* vert-edge
* --------- */
{
- unsigned int i_a;
+ uint i_a;
for (i_a = 0; i_a < 3; i_a++) {
if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A) == 0) {
- unsigned int i_b_e0;
+ uint 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;
+ uint i_b_e1 = (i_b_e0 + 1) % 3;
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))
@@ -644,12 +644,12 @@ static void bm_isect_tri_tri(
}
{
- unsigned int i_b;
+ uint i_b;
for (i_b = 0; i_b < 3; i_b++) {
if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B) == 0) {
- unsigned int i_a_e0;
+ uint 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;
+ uint i_a_e1 = (i_a_e0 + 1) % 3;
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))
@@ -689,7 +689,7 @@ static void bm_isect_tri_tri(
{
float t_scale[3][3];
- unsigned int i_a;
+ uint i_a;
copy_v3_v3(t_scale[0], fv_b[0]->co);
copy_v3_v3(t_scale[1], fv_b[1]->co);
@@ -717,7 +717,7 @@ static void bm_isect_tri_tri(
{
float t_scale[3][3];
- unsigned int i_b;
+ uint i_b;
copy_v3_v3(t_scale[0], fv_a[0]->co);
copy_v3_v3(t_scale[1], fv_a[1]->co);
@@ -757,8 +757,8 @@ static void bm_isect_tri_tri(
/* edge-tri & edge-edge
* -------------------- */
{
- for (unsigned int i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
- unsigned int i_a_e1 = (i_a_e0 + 1) % 3;
+ for (uint i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
+ uint i_a_e1 = (i_a_e0 + 1) % 3;
enum ISectType side;
BMVert *iv;
@@ -778,8 +778,8 @@ static void bm_isect_tri_tri(
}
}
- for (unsigned int i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
- unsigned int i_b_e1 = (i_b_e0 + 1) % 3;
+ for (uint i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
+ uint i_b_e1 = (i_b_e0 + 1) % 3;
enum ISectType side;
BMVert *iv;
@@ -956,7 +956,7 @@ static int isect_bvhtree_point_v3(
const float *depth_arr = z_buffer.data;
float depth_last = depth_arr[0];
- for (unsigned int i = 1; i < z_buffer.count; i++) {
+ for (uint i = 1; i < z_buffer.count; i++) {
if (depth_arr[i] - depth_last > eps) {
depth_last = depth_arr[i];
num_isect++;
@@ -986,7 +986,7 @@ bool BM_mesh_intersect(
struct BMLoop *(*looptris)[3], const int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data), void *user_data,
const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect,
- const int boolean_mode,
+ const bool use_edge_tag, const int boolean_mode,
const float eps)
{
struct ISectState s;
@@ -1000,7 +1000,7 @@ bool BM_mesh_intersect(
#ifdef USE_BVH
BVHTree *tree_a, *tree_b;
- unsigned int tree_overlap_tot;
+ uint tree_overlap_tot;
BVHTreeOverlap *overlap;
#else
int i_a, i_b;
@@ -1117,7 +1117,7 @@ bool BM_mesh_intersect(
overlap = BLI_bvhtree_overlap(tree_b, tree_a, &tree_overlap_tot, NULL, NULL);
if (overlap) {
- unsigned int i;
+ uint i;
for (i = 0; i < tree_overlap_tot; i++) {
#ifdef USE_DUMP
@@ -1390,7 +1390,7 @@ bool BM_mesh_intersect(
GHASH_ITER (gh_iter, s.face_edges) {
struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
LinkNode **node_prev_p;
- unsigned int i;
+ uint i;
node_prev_p = &e_ls_base->list;
for (i = 0, node = e_ls_base->list; node; i++, node = node->next) {
@@ -1455,7 +1455,7 @@ bool BM_mesh_intersect(
}
{
- unsigned int i;
+ uint i;
for (i = 0; i < STACK_SIZE(splice_ls); i++) {
if (!BLI_gset_haskey(verts_invalid, splice_ls[i][0]) &&
!BLI_gset_haskey(verts_invalid, splice_ls[i][1]))
@@ -1526,7 +1526,7 @@ bool BM_mesh_intersect(
BM_mesh_edgesplit(bm, false, true, false);
}
- else if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
+ else if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE || use_edge_tag) {
GSetIterator gs_iter;
/* no need to clear for boolean */
@@ -1610,7 +1610,7 @@ bool BM_mesh_intersect(
#ifdef USE_BOOLEAN_RAYCAST_DRAW
{
- unsigned int colors[4] = {0x00000000, 0xffffffff, 0xff000000, 0x0000ff};
+ uint colors[4] = {0x00000000, 0xffffffff, 0xff000000, 0x0000ff};
float co_other[3] = {UNPACK3(co)};
co_other[0] += 1000.0f;
bl_debug_color_set(colors[(hits & 1) == 1]);
diff --git a/source/blender/bmesh/tools/bmesh_intersect.h b/source/blender/bmesh/tools/bmesh_intersect.h
index d0cc41654eb..51926a01710 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.h
+++ b/source/blender/bmesh/tools/bmesh_intersect.h
@@ -30,7 +30,7 @@ bool BM_mesh_intersect(
struct BMLoop *(*looptris)[3], const int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data), void *user_data,
const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect,
- const int boolean_mode,
+ const bool use_edge_tag, const int boolean_mode,
const float eps);
enum {
diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c
index 30b083cacda..85c591b6684 100644
--- a/source/blender/bmesh/tools/bmesh_path.c
+++ b/source/blender/bmesh/tools/bmesh_path.c
@@ -38,24 +38,34 @@
/* -------------------------------------------------------------------- */
/* Generic Helpers */
-static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3[3])
+/**
+ * Use skip options when we want to start measuring from a boundary.
+ */
+static float step_cost_3_v3_ex(
+ const float v1[3], const float v2[3], const float v3[3],
+ bool skip_12, bool skip_23)
{
- float cost, d1[3], d2[3];
-
+ float d1[3], d2[3];
/* The cost is based on the simple sum of the length of the two edgees... */
sub_v3_v3v3(d1, v2, v1);
sub_v3_v3v3(d2, v3, v2);
- cost = normalize_v3(d1) + normalize_v3(d2);
+ const float cost_12 = normalize_v3(d1);
+ const float cost_23 = normalize_v3(d2);
+ const float cost = ((skip_12 ? 0.0f : cost_12) +
+ (skip_23 ? 0.0f : cost_23));
/* but is biased to give higher values to sharp turns, so that it will take
* paths with fewer "turns" when selecting between equal-weighted paths between
* the two edges */
- cost = cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2)))));
-
- return cost;
+ return cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2)))));
}
+static float step_cost_3_v3(
+ const float v1[3], const float v2[3], const float v3[3])
+{
+ return step_cost_3_v3_ex(v1, v2, v3, false, false);
+}
/* -------------------------------------------------------------------- */
@@ -364,7 +374,7 @@ LinkNode *BM_mesh_calc_path_edge(
/* -------------------------------------------------------------------- */
/* BM_mesh_calc_path_face */
-static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e)
+static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e, const void * const f_endpoints[2])
{
float f_a_cent[3];
float f_b_cent[3];
@@ -392,10 +402,12 @@ static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e)
}
#endif
- return step_cost_3_v3(f_a_cent, e_cent, f_b_cent);
+ return step_cost_3_v3_ex(
+ f_a_cent, e_cent, f_b_cent,
+ (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
}
-static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v)
+static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v, const void * const f_endpoints[2])
{
float f_a_cent[3];
float f_b_cent[3];
@@ -403,12 +415,14 @@ static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v)
BM_face_calc_center_mean_weighted(f_a, f_a_cent);
BM_face_calc_center_mean_weighted(f_b, f_b_cent);
- return step_cost_3_v3(f_a_cent, v->co, f_b_cent);
+ return step_cost_3_v3_ex(
+ f_a_cent, v->co, f_b_cent,
+ (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
}
static void facetag_add_adjacent(
Heap *heap, BMFace *f_a, BMFace **faces_prev, float *cost,
- const struct BMCalcPathParams *params)
+ const void * const f_endpoints[2], const struct BMCalcPathParams *params)
{
const int f_a_index = BM_elem_index_get(f_a);
@@ -427,7 +441,7 @@ static void facetag_add_adjacent(
/* we know 'f_b' is not visited, check it out! */
const int f_b_index = BM_elem_index_get(f_b);
const float cost_cut = params->use_topology_distance ?
- 1.0f : facetag_cut_cost_edge(f_a, f_b, l_iter->e);
+ 1.0f : facetag_cut_cost_edge(f_a, f_b, l_iter->e, f_endpoints);
const float cost_new = cost[f_a_index] + cost_cut;
if (cost[f_b_index] > cost_new) {
@@ -454,7 +468,7 @@ static void facetag_add_adjacent(
/* we know 'f_b' is not visited, check it out! */
const int f_b_index = BM_elem_index_get(f_b);
const float cost_cut = params->use_topology_distance ?
- 1.0f : facetag_cut_cost_vert(f_a, f_b, l_a->v);
+ 1.0f : facetag_cut_cost_vert(f_a, f_b, l_a->v, f_endpoints);
const float cost_new = cost[f_a_index] + cost_cut;
if (cost[f_b_index] > cost_new) {
@@ -482,6 +496,9 @@ LinkNode *BM_mesh_calc_path_face(
BMFace **faces_prev;
int i, totface;
+ /* Start measuring face path at the face edges, ignoring their centers. */
+ const void * const f_endpoints[2] = {f_src, f_dst};
+
/* note, would pass BM_EDGE except we are looping over all faces anyway */
// BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
@@ -522,7 +539,7 @@ LinkNode *BM_mesh_calc_path_face(
if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
- facetag_add_adjacent(heap, f, faces_prev, cost, params);
+ facetag_add_adjacent(heap, f, faces_prev, cost, f_endpoints, params);
}
}
diff --git a/source/blender/bmesh/tools/bmesh_path.h b/source/blender/bmesh/tools/bmesh_path.h
index b6de5e0e4e0..fbdd2296121 100644
--- a/source/blender/bmesh/tools/bmesh_path.h
+++ b/source/blender/bmesh/tools/bmesh_path.h
@@ -28,8 +28,8 @@
*/
struct BMCalcPathParams {
- unsigned int use_topology_distance : 1;
- unsigned int use_step_face : 1;
+ uint use_topology_distance : 1;
+ uint use_step_face : 1;
};
struct LinkNode *BM_mesh_calc_path_vert(
diff --git a/source/blender/bmesh/tools/bmesh_path_region.c b/source/blender/bmesh/tools/bmesh_path_region.c
index aad1f9c5a49..d23ea537d82 100644
--- a/source/blender/bmesh/tools/bmesh_path_region.c
+++ b/source/blender/bmesh/tools/bmesh_path_region.c
@@ -29,22 +29,32 @@
#include "BLI_math.h"
#include "BLI_linklist.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BLI_alloca.h"
#include "bmesh.h"
#include "bmesh_path_region.h" /* own include */
-/* Special handling of vertices with 2 edges
- * (act as if the edge-chain is a single edge). */
+/**
+ * Special handling of vertices with 2 edges
+ * (act as if the edge-chain is a single edge).
+ *
+ * \note Regarding manifold edge stepping: #BM_vert_is_edge_pair_manifold usage.
+ * Logic to skip a chain of vertices is not applied at boundaries because it gives
+ * strange behavior from a user perspective especially with boundary quads, see: T52701
+ *
+ * Restrict walking over a vertex chain to cases where the edges share the same faces.
+ * This is more typical of what a user would consider a vertex chain.
+ */
#define USE_EDGE_CHAIN
#ifdef USE_EDGE_CHAIN
/**
- * Takes a vertex with 2 edge users and fills in the vertices at each end-point,
- * or nothing if if the edges loop back to its self.
+ * Takes a vertex with 2 edge users and assigns the vertices at each end-point,
+ *
+ * \return Success when \a v_end_pair values are set or false if the edges loop back on themselves.
*/
static bool bm_vert_pair_ends(BMVert *v_pivot, BMVert *v_end_pair[2])
{
@@ -53,7 +63,7 @@ static bool bm_vert_pair_ends(BMVert *v_pivot, BMVert *v_end_pair[2])
do {
BMEdge *e_chain = e;
BMVert *v_other = BM_edge_other_vert(e_chain, v_pivot);
- while (BM_vert_is_edge_pair(v_other)) {
+ while (BM_vert_is_edge_pair_manifold(v_other)) {
BMEdge *e_chain_next = BM_DISK_EDGE_NEXT(e_chain, v_other);
BLI_assert(BM_DISK_EDGE_NEXT(e_chain_next, v_other) == e_chain);
v_other = BM_edge_other_vert(e_chain_next, v_other);
@@ -88,7 +98,7 @@ static bool bm_vert_region_test_chain(BMVert *v, int * const depths[2], const in
if (bm_vert_region_test(v, depths, pass)) {
return true;
}
- else if (BM_vert_is_edge_pair(v) &&
+ else if (BM_vert_is_edge_pair_manifold(v) &&
bm_vert_pair_ends(v, v_end_pair) &&
bm_vert_region_test(v_end_pair[0], depths, pass) &&
bm_vert_region_test(v_end_pair[1], depths, pass))
@@ -206,7 +216,7 @@ static LinkNode *mesh_calc_path_region_elem(
for (int i = 0; i < ele_verts_len[side]; i++) {
BMVert *v = ele_verts[side][i];
BMVert *v_end_pair[2];
- if (BM_vert_is_edge_pair(v) && bm_vert_pair_ends(v, v_end_pair)) {
+ if (BM_vert_is_edge_pair_manifold(v) && bm_vert_pair_ends(v, v_end_pair)) {
for (int j = 0; j < 2; j++) {
const int v_end_index = BM_elem_index_get(v_end_pair[j]);
if (depths[side][v_end_index] == -1) {
@@ -239,7 +249,7 @@ static LinkNode *mesh_calc_path_region_elem(
/* Walk along the chain, fill in values until we reach a vertex with 3+ edges. */
{
BMEdge *e_chain = e;
- while (BM_vert_is_edge_pair(v_b) &&
+ while (BM_vert_is_edge_pair_manifold(v_b) &&
((depths[side][v_b_index] == -1)))
{
depths[side][v_b_index] = pass;
@@ -256,7 +266,7 @@ static LinkNode *mesh_calc_path_region_elem(
/* Add the other vertex to the stack, to be traversed in the next pass. */
if (depths[side][v_b_index] == -1) {
#ifdef USE_EDGE_CHAIN
- BLI_assert(!BM_vert_is_edge_pair(v_b));
+ BLI_assert(!BM_vert_is_edge_pair_manifold(v_b));
#endif
BLI_assert(pass == depths[side][BM_elem_index_get(v_a)] + 1);
depths[side][v_b_index] = pass;
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index a6860a6614a..2abf8f2c46e 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -114,7 +114,7 @@ typedef struct UUIDWalk {
GHash *faces_from_uuid; /* UUID -> UUIDFaceStepItem */
UUID_Int *rehash_store;
- unsigned int rehash_store_len;
+ uint rehash_store_len;
} cache;
} UUIDWalk;
@@ -136,7 +136,7 @@ typedef struct UUIDFaceStepItem {
uintptr_t uuid;
LinkNode *list;
- unsigned int list_len;
+ uint list_len;
} UUIDFaceStepItem;
BLI_INLINE bool bm_uuidwalk_face_test(
@@ -178,10 +178,10 @@ BLI_INLINE bool bm_uuidwalk_face_lookup(
}
}
-static unsigned int ghashutil_bmelem_indexhash(const void *key)
+static uint ghashutil_bmelem_indexhash(const void *key)
{
const BMElem *ele = key;
- return (unsigned int)BM_elem_index_get(ele);
+ return (uint)BM_elem_index_get(ele);
}
static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
@@ -192,14 +192,14 @@ static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
static GHash *ghash_bmelem_new_ex(
const char *info,
- const unsigned int nentries_reserve)
+ const uint nentries_reserve)
{
return BLI_ghash_new_ex(ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
}
static GSet *gset_bmelem_new_ex(
const char *info,
- const unsigned int nentries_reserve)
+ const uint nentries_reserve)
{
return BLI_gset_new_ex(ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
}
@@ -218,8 +218,8 @@ static GSet *gset_bmelem_new(const char *info)
static void bm_uuidwalk_init(
UUIDWalk *uuidwalk,
- const unsigned int faces_src_region_len,
- const unsigned int verts_src_region_len)
+ const uint faces_src_region_len,
+ const uint verts_src_region_len)
{
BLI_listbase_clear(&uuidwalk->faces_step);
@@ -307,7 +307,7 @@ static UUID_Int bm_uuidwalk_calc_vert_uuid(
/* vert -> other */
{
- unsigned int tot = 0;
+ uint tot = 0;
BMIter eiter;
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
@@ -323,7 +323,7 @@ static UUID_Int bm_uuidwalk_calc_vert_uuid(
/* faces */
{
- unsigned int tot = 0;
+ uint tot = 0;
BMIter iter;
BMFace *f;
@@ -357,7 +357,7 @@ static UUID_Int bm_uuidwalk_calc_face_uuid(
UUID_Int uuid;
- uuid = uuidwalk->pass * (unsigned int)f->len * PRIME_FACE_LARGE;
+ uuid = uuidwalk->pass * (uint)f->len * PRIME_FACE_LARGE;
/* face-verts */
{
@@ -399,7 +399,7 @@ static UUID_Int bm_uuidwalk_calc_face_uuid(
}
static void bm_uuidwalk_rehash_reserve(
- UUIDWalk *uuidwalk, unsigned int rehash_store_len_new)
+ UUIDWalk *uuidwalk, uint rehash_store_len_new)
{
if (UNLIKELY(rehash_store_len_new > uuidwalk->cache.rehash_store_len)) {
/* avoid re-allocs */
@@ -419,9 +419,9 @@ static void bm_uuidwalk_rehash(
{
GHashIterator gh_iter;
UUID_Int *uuid_store;
- unsigned int i;
+ uint i;
- unsigned int rehash_store_len_new = MAX2(BLI_ghash_size(uuidwalk->verts_uuid),
+ uint rehash_store_len_new = MAX2(BLI_ghash_size(uuidwalk->verts_uuid),
BLI_ghash_size(uuidwalk->faces_uuid));
bm_uuidwalk_rehash_reserve(uuidwalk, rehash_store_len_new);
@@ -454,12 +454,12 @@ static void bm_uuidwalk_rehash(
static void bm_uuidwalk_rehash_facelinks(
UUIDWalk *uuidwalk,
- LinkNode *faces, const unsigned int faces_len,
+ LinkNode *faces, const uint faces_len,
const bool is_init)
{
UUID_Int *uuid_store;
LinkNode *f_link;
- unsigned int i;
+ uint i;
bm_uuidwalk_rehash_reserve(uuidwalk, faces_len);
uuid_store = uuidwalk->cache.rehash_store;
@@ -502,7 +502,7 @@ static bool bm_vert_is_uuid_connect(
}
static void bm_uuidwalk_pass_add(
- UUIDWalk *uuidwalk, LinkNode *faces_pass, const unsigned int faces_pass_len)
+ UUIDWalk *uuidwalk, LinkNode *faces_pass, const uint faces_pass_len)
{
GHashIterator gh_iter;
GHash *verts_uuid_pass;
@@ -511,7 +511,7 @@ static void bm_uuidwalk_pass_add(
UUIDFaceStep *fstep;
- BLI_assert(faces_pass_len == (unsigned int)BLI_linklist_count(faces_pass));
+ BLI_assert(faces_pass_len == (uint)BLI_linklist_count(faces_pass));
/* rehash faces now all their verts have been added */
bm_uuidwalk_rehash_facelinks(uuidwalk, faces_pass, faces_pass_len, true);
@@ -588,13 +588,13 @@ static int bm_face_len_cmp(const void *v1, const void *v2)
else return 0;
}
-static unsigned int bm_uuidwalk_init_from_edge(
+static uint bm_uuidwalk_init_from_edge(
UUIDWalk *uuidwalk, BMEdge *e)
{
BMLoop *l_iter = e->l;
- unsigned int f_arr_len = (unsigned int)BM_edge_face_count(e);
+ uint f_arr_len = (uint)BM_edge_face_count(e);
BMFace **f_arr = BLI_array_alloca(f_arr, f_arr_len);
- unsigned int fstep_num = 0, i = 0;
+ uint fstep_num = 0, i = 0;
do {
BMFace *f = l_iter->f;
@@ -619,7 +619,7 @@ static unsigned int bm_uuidwalk_init_from_edge(
* elsewhere using LinkNode's makes more sense */
for (i = 0; i < f_arr_len; ) {
LinkNode *faces_pass = NULL;
- const unsigned int i_init = i;
+ const uint i_init = i;
const int f_len = f_arr[i]->len;
do {
@@ -750,9 +750,9 @@ static BMFace **bm_mesh_region_match_pair(
UUIDWalk *w_src, UUIDWalk *w_dst,
#endif
BMEdge *e_src, BMEdge *e_dst,
- const unsigned int faces_src_region_len,
- const unsigned int verts_src_region_len,
- unsigned int *r_faces_result_len)
+ const uint faces_src_region_len,
+ const uint verts_src_region_len,
+ uint *r_faces_result_len)
{
#ifndef USE_WALKER_REUSE
UUIDWalk w_src_, w_dst_;
@@ -877,8 +877,8 @@ static BMFace **bm_mesh_region_match_pair(
if (found) {
GHashIterator gh_iter;
- const unsigned int faces_result_len = BLI_ghash_size(w_dst->faces_uuid);
- unsigned int i;
+ const uint faces_result_len = BLI_ghash_size(w_dst->faces_uuid);
+ uint i;
faces_result = MEM_mallocN(sizeof(*faces_result) * (faces_result_len + 1), __func__);
GHASH_ITER_INDEX (gh_iter, w_dst->faces_uuid, i) {
@@ -909,12 +909,12 @@ finally:
* Tag as visited, avoid re-use.
*/
static void bm_face_array_visit(
- BMFace **faces, const unsigned int faces_len,
- unsigned int *r_verts_len,
+ BMFace **faces, const uint faces_len,
+ uint *r_verts_len,
bool visit_faces)
{
- unsigned int verts_len = 0;
- unsigned int i;
+ uint verts_len = 0;
+ uint i;
for (i = 0; i < faces_len; i++) {
BMFace *f = faces[i];
BMLoop *l_iter, *l_first;
@@ -1081,9 +1081,9 @@ static SUID_Int bm_face_region_vert_pass_id(GHash *gh, BMVert *v)
* This is only called once on the source region (no need to be highly optimized).
*/
static BMEdge *bm_face_region_pivot_edge_find(
- BMFace **faces_region, unsigned int faces_region_len,
- unsigned int verts_region_len,
- unsigned int *r_depth)
+ BMFace **faces_region, uint faces_region_len,
+ uint verts_region_len,
+ uint *r_depth)
{
/* note, keep deterministic where possible (geometry order independent)
* this function assumed all visit faces & edges are tagged */
@@ -1092,7 +1092,7 @@ static BMEdge *bm_face_region_pivot_edge_find(
BLI_LINKSTACK_DECLARE(vert_queue_next, BMVert *);
GHash *gh = BLI_ghash_ptr_new(__func__);
- unsigned int i;
+ uint i;
BMEdge *e_pivot = NULL;
/* pick any non-boundary edge (not ideal) */
@@ -1101,7 +1101,7 @@ static BMEdge *bm_face_region_pivot_edge_find(
SUID_Int pass = 0;
/* total verts in 'gs' we have visited - aka - not v_init_none */
- unsigned int vert_queue_used = 0;
+ uint vert_queue_used = 0;
BLI_LINKSTACK_INIT(vert_queue_prev);
BLI_LINKSTACK_INIT(vert_queue_next);
@@ -1115,7 +1115,7 @@ static BMEdge *bm_face_region_pivot_edge_find(
do {
BMEdge *e = l_iter->e;
if (bm_edge_is_region_boundary(e)) {
- unsigned int j;
+ uint j;
for (j = 0; j < 2; j++) {
void **val_p;
if (!BLI_ghash_ensure_p(gh, (&e->v1)[j], &val_p)) {
@@ -1251,7 +1251,7 @@ static BMEdge *bm_face_region_pivot_edge_find(
pass = 0;
}
- *r_depth = (unsigned int)pass;
+ *r_depth = (uint)pass;
return e_pivot;
}
@@ -1286,7 +1286,7 @@ static UUIDFashMatch bm_vert_fasthash_single(BMVert *v)
e_num += 1;
do {
f_num += 1;
- l_num += (unsigned int)l_iter->f->len;
+ l_num += (uint)l_iter->f->len;
} while ((l_iter = l_iter->radial_next) != e->l);
}
}
@@ -1301,16 +1301,16 @@ static UUIDFashMatch bm_vert_fasthash_single(BMVert *v)
}
static UUIDFashMatch *bm_vert_fasthash_create(
- BMesh *bm, const unsigned int depth)
+ BMesh *bm, const uint depth)
{
UUIDFashMatch *id_prev;
UUIDFashMatch *id_curr;
- unsigned int pass, i;
+ uint pass, i;
BMVert *v;
BMIter iter;
- id_prev = MEM_mallocN(sizeof(*id_prev) * (unsigned int)bm->totvert, __func__);
- id_curr = MEM_mallocN(sizeof(*id_curr) * (unsigned int)bm->totvert, __func__);
+ id_prev = MEM_mallocN(sizeof(*id_prev) * (uint)bm->totvert, __func__);
+ id_curr = MEM_mallocN(sizeof(*id_curr) * (uint)bm->totvert, __func__);
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
id_prev[i] = bm_vert_fasthash_single(v);
@@ -1319,7 +1319,7 @@ static UUIDFashMatch *bm_vert_fasthash_create(
for (pass = 0; pass < depth; pass++) {
BMEdge *e;
- memcpy(id_curr, id_prev, sizeof(*id_prev) * (unsigned int)bm->totvert);
+ memcpy(id_curr, id_prev, sizeof(*id_prev) * (uint)bm->totvert);
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_edge_is_wire(e) == false) {
@@ -1379,16 +1379,16 @@ static void bm_vert_fasthash_destroy(
*/
int BM_mesh_region_match(
BMesh *bm,
- BMFace **faces_region, unsigned int faces_region_len,
+ BMFace **faces_region, uint faces_region_len,
ListBase *r_face_regions)
{
BMEdge *e_src;
BMEdge *e_dst;
BMIter iter;
- unsigned int verts_region_len = 0;
- unsigned int faces_result_len = 0;
+ uint verts_region_len = 0;
+ uint faces_result_len = 0;
/* number of steps from e_src to a boundary vert */
- unsigned int depth;
+ uint depth;
#ifdef USE_WALKER_REUSE
@@ -1457,7 +1457,7 @@ int BM_mesh_region_match(
BM_ITER_MESH (e_dst, &iter, bm, BM_EDGES_OF_MESH) {
BMFace **faces_result;
- unsigned int faces_result_len_out;
+ uint faces_result_len_out;
if (BM_elem_flag_test(e_dst, BM_ELEM_TAG) || BM_edge_is_wire(e_dst)) {
continue;
diff --git a/source/blender/bmesh/tools/bmesh_region_match.h b/source/blender/bmesh/tools/bmesh_region_match.h
index edf8369b070..8ef138629b8 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.h
+++ b/source/blender/bmesh/tools/bmesh_region_match.h
@@ -27,7 +27,7 @@
int BM_mesh_region_match(
BMesh *bm,
- BMFace **faces_region, unsigned int faces_region_len,
+ BMFace **faces_region, uint faces_region_len,
ListBase *r_face_regions);
#endif /* __BMESH_REGION_MATCH_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_separate.c b/source/blender/bmesh/tools/bmesh_separate.c
new file mode 100644
index 00000000000..287b4125330
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_separate.c
@@ -0,0 +1,133 @@
+/*
+ * ***** 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/bmesh/tools/bmesh_separate.c
+ * \ingroup bmesh
+ *
+ * BMesh separate, disconnects a set of faces from all others,
+ * so they don't share any vertices/edges with other faces.
+ */
+
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_buffer.h"
+
+#include "bmesh.h"
+#include "intern/bmesh_private.h"
+#include "bmesh_separate.h" /* own include */
+
+/**
+ * Split all faces that match `filter_fn`.
+ * \note
+ */
+void BM_mesh_separate_faces(
+ BMesh *bm,
+ BMFaceFilterFunc filter_fn, void *user_data)
+{
+ BMFace **faces_array_all = MEM_mallocN(bm->totface * sizeof(BMFace *), __func__);
+ /*
+ * - Create an array of faces based on 'filter_fn'.
+ * First part of array for match, for non-match.
+ *
+ * - Enable all vertex tags, then clear all tagged vertices from 'faces_b'.
+ *
+ * - Loop over 'faces_a', checking each vertex,
+ * splitting out any which aren't tagged (and therefor shared), disabling tags as we go.
+ */
+
+ BMFace *f;
+ BMIter iter;
+
+ uint faces_a_len = 0;
+ uint faces_b_len = 0;
+ {
+ int i_a = 0;
+ int i_b = bm->totface;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ faces_array_all[filter_fn(f, user_data) ? i_a++ : --i_b] = f;
+ }
+ faces_a_len = i_a;
+ faces_b_len = bm->totface - i_a;
+ }
+
+ BMFace **faces_a = faces_array_all;
+ BMFace **faces_b = faces_array_all + faces_a_len;
+
+ /* Enable for all */
+ BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+
+ /* Disable vert tag on faces_b */
+ for (uint i = 0; i < faces_b_len; i++) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(faces_b[i]);
+ do {
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+
+ BLI_buffer_declare_static(BMLoop **, loop_split, 0, 128);
+
+ /* Check shared verts ('faces_a' tag and disable) */
+ for (uint i = 0; i < faces_a_len; i++) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(faces_a[i]);
+ do {
+ if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
+ BMVert *v = l_iter->v;
+ /* Enable, since we may visit this vertex again on other faces */
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+
+ /* We know the vertex is shared, collect all vertices and split them off. */
+
+ /* Fill 'loop_split' */
+ {
+ BMEdge *e_first, *e_iter;
+ e_iter = e_first = l_iter->e;
+ do {
+ if (e_iter->l != NULL) {
+ BMLoop *l_radial_first, *l_radial_iter;
+ l_radial_first = l_radial_iter = e_iter->l;
+ do {
+ if (l_radial_iter->v == v) {
+ if (filter_fn(l_radial_iter->f, user_data)) {
+ BLI_buffer_append(&loop_split, BMLoop *, l_radial_iter);
+ }
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+
+ /* Perform the split */
+ BM_face_loop_separate_multi(bm, loop_split.data, loop_split.count);
+
+ BLI_buffer_empty(&loop_split);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ BLI_buffer_free(&loop_split);
+
+ MEM_freeN(faces_array_all);
+}
diff --git a/source/blender/bmesh/tools/bmesh_separate.h b/source/blender/bmesh/tools/bmesh_separate.h
new file mode 100644
index 00000000000..91b2b71c872
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_separate.h
@@ -0,0 +1,32 @@
+/*
+ * ***** 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 __BMESH_SEPARATE_H__
+#define __BMESH_SEPARATE_H__
+
+/** \file blender/bmesh/tools/bmesh_separate.h
+ * \ingroup bmesh
+ */
+
+void BM_mesh_separate_faces(
+ BMesh *bm,
+ BMFaceFilterFunc filter_fn, void *user_data);
+
+#endif /* __BMESH_SEPARATE_H__ */
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index 3bff20e846b..d4f434d56fd 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -312,12 +312,12 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
if (ob->type == OB_ARMATURE) {
ob_name = getObjectBoneName(ob, fcu);
BLI_snprintf(
- anim_id,
- sizeof(anim_id),
- "%s_%s.%s",
- (char *)translate_id(ob_name).c_str(),
- (char *)translate_id(transformName).c_str(),
- axis_name);
+ anim_id,
+ sizeof(anim_id),
+ "%s_%s.%s",
+ (char *)translate_id(ob_name).c_str(),
+ (char *)translate_id(transformName).c_str(),
+ axis_name);
}
else {
if (ma)
@@ -326,12 +326,12 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
ob_name = id_name(ob);
BLI_snprintf(
- anim_id,
- sizeof(anim_id),
- "%s_%s_%s",
- (char *)translate_id(ob_name).c_str(),
- (char *)getAnimationPathId(fcu).c_str(),
- axis_name);
+ anim_id,
+ sizeof(anim_id),
+ "%s_%s_%s",
+ (char *)translate_id(ob_name).c_str(),
+ (char *)getAnimationPathId(fcu).c_str(),
+ axis_name);
}
openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
@@ -530,7 +530,7 @@ void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_
addSampler(sampler);
- std::string target = translate_id(bone_name) + "/transform";
+ std::string target = get_joint_id(bone, ob_arm) + "/transform";
addChannel(COLLADABU::URI(empty, sampler_id), target);
closeAnimation();
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 5cd01eff263..bd47ee0214d 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -35,8 +35,8 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -1934,7 +1934,7 @@ Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, COLLADAFW::No
mul_m4_m4m4(mat, ipar, temp);
}
- TransformBase::decompose(mat, job->loc, NULL, job->quat, job->size);
+ bc_decompose(mat, job->loc, NULL, job->quat, job->size);
if (par_job) {
job->parent = par_job;
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 4f5cf83f5ca..d2495a8cb9f 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -69,17 +69,21 @@ void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce,
// write bone nodes
bArmature * armature = (bArmature *)ob_arm->data;
- ED_armature_to_edit(armature);
+ bool is_edited = armature->edbo != NULL;
- bArmature *arm = (bArmature *)ob_arm->data;
- for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next) {
+ if (!is_edited)
+ ED_armature_to_edit(armature);
+
+ for (Bone *bone = (Bone *)armature->bonebase.first; bone; bone = bone->next) {
// start from root bones
if (!bone->parent)
add_bone_node(bone, ob_arm, sce, se, child_objects);
}
- ED_armature_from_edit(armature);
- ED_armature_edit_free(armature);
+ if (!is_edited) {
+ ED_armature_from_edit(armature);
+ ED_armature_edit_free(armature);
+ }
}
void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
@@ -112,7 +116,10 @@ bool ArmatureExporter::add_instance_controller(Object *ob)
write_bone_URLs(ins, ob_arm, bone);
}
- InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only);
+ InstanceWriter::add_material_bindings(ins.getBindMaterial(),
+ ob,
+ this->export_settings->active_uv_only,
+ this->export_settings->export_texture_type);
ins.add();
return true;
@@ -152,11 +159,6 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O
}
#endif
-std::string ArmatureExporter::get_joint_sid(Bone *bone, Object *ob_arm)
-{
- return get_joint_id(bone, ob_arm);
-}
-
// parent_mat is armature-space
void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce,
SceneExporter *se,
@@ -257,47 +259,59 @@ void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW:
//bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
float mat[4][4];
+ float bone_rest_mat[4][4]; /* derived from bone->arm_mat */
+ float parent_rest_mat[4][4]; /* derived from bone->parent->arm_mat */
- if (bone->parent) {
- // get bone-space matrix from parent pose
- /*bPoseChannel *parchan = BKE_pose_channel_find_name(ob_arm->pose, bone->parent->name);
- float invpar[4][4];
- invert_m4_m4(invpar, parchan->pose_mat);
- mul_m4_m4m4(mat, invpar, pchan->pose_mat);*/
-
- float invpar[4][4];
- invert_m4_m4(invpar, bone->parent->arm_mat);
- mul_m4_m4m4(mat, invpar, bone->arm_mat);
+ bool has_restmat = bc_get_property_matrix(bone, "rest_mat", mat);
- }
- else {
+ if (!has_restmat) {
+
+ /* Have no restpose matrix stored, try old style <= Blender 2.78 */
- //copy_m4_m4(mat, pchan->pose_mat);
- //pose mat is object space
- //New change: export bone->arm_mat
- copy_m4_m4(mat, bone->arm_mat);
- }
+ bc_create_restpose_mat(this->export_settings, bone, bone_rest_mat, bone->arm_mat, true);
- // OPEN_SIM_COMPATIBILITY
- if (export_settings->open_sim) {
- // Remove rotations vs armature from transform
- // parent_rest_rot * mat * irest_rot
- float temp[4][4];
- copy_m4_m4(temp, bone->arm_mat);
- temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
- invert_m4(temp);
+ if (bone->parent) {
+ // get bone-space matrix from parent pose
+ /*bPoseChannel *parchan = BKE_pose_channel_find_name(ob_arm->pose, bone->parent->name);
+ float invpar[4][4];
+ invert_m4_m4(invpar, parchan->pose_mat);
+ mul_m4_m4m4(mat, invpar, pchan->pose_mat);*/
+ float invpar[4][4];
+ bc_create_restpose_mat(this->export_settings, bone->parent, parent_rest_mat, bone->parent->arm_mat, true);
- mul_m4_m4m4(mat, mat, temp);
+ invert_m4_m4(invpar, parent_rest_mat);
+ mul_m4_m4m4(mat, invpar, bone_rest_mat);
- if (bone->parent) {
- copy_m4_m4(temp, bone->parent->arm_mat);
+ }
+ else {
+ copy_m4_m4(mat, bone_rest_mat);
+ }
+
+ // OPEN_SIM_COMPATIBILITY
+ if (export_settings->open_sim) {
+ // Remove rotations vs armature from transform
+ // parent_rest_rot * mat * irest_rot
+ float temp[4][4];
+ copy_m4_m4(temp, bone_rest_mat);
temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
+ invert_m4(temp);
+
+ mul_m4_m4m4(mat, mat, temp);
- mul_m4_m4m4(mat, temp, mat);
+ if (bone->parent) {
+ copy_m4_m4(temp, parent_rest_mat);
+ temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
+
+ mul_m4_m4m4(mat, temp, mat);
+ }
}
}
+ if (this->export_settings->limit_precision)
+ bc_sanitize_mat(mat, 6);
+
TransformWriter::add_node_transform(node, mat, NULL);
+
}
std::string ArmatureExporter::get_controller_id(Object *ob_arm, Object *ob)
diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h
index 883a6aca847..d271b505aa9 100644
--- a/source/blender/collada/ArmatureExporter.h
+++ b/source/blender/collada/ArmatureExporter.h
@@ -83,8 +83,6 @@ private:
void find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce);
#endif
- std::string get_joint_sid(Bone *bone, Object *ob_arm);
-
// Scene, SceneExporter and the list of child_objects
// are required for writing bone parented objects
void add_bone_node(Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se,
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index ae43c0a69d2..0ea8324ed7c 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -32,6 +32,7 @@
#include "COLLADAFWUniqueId.h"
+extern "C" {
#include "BKE_action.h"
#include "BKE_depsgraph.h"
#include "BKE_object.h"
@@ -39,7 +40,9 @@
#include "BLI_string.h"
#include "BLI_listbase.h"
#include "ED_armature.h"
+}
+#include "collada_utils.h"
#include "ArmatureImporter.h"
// use node name, or fall back to original id if not present (name is optional)
@@ -91,6 +94,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
{
float mat[4][4];
float joint_inv_bind_mat[4][4];
+ float joint_bind_mat[4][4];
int chain_length = 0;
//Checking if bone is already made.
@@ -106,7 +110,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
*/
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator skin_it;
- bool bone_is_not_skinned = true;
+ bool bone_is_skinned = false;
for (skin_it = skin_by_data_uid.begin(); skin_it != skin_by_data_uid.end(); skin_it++) {
SkinInfo *b = &skin_it->second;
@@ -114,7 +118,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
// get original world-space matrix
invert_m4_m4(mat, joint_inv_bind_mat);
-
+ copy_m4_m4(joint_bind_mat, mat);
// And make local to armature
Object *ob_arm = skin->BKE_armature_from_object();
if (ob_arm) {
@@ -123,24 +127,14 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
mul_m4_m4m4(mat, invmat, mat);
}
- bone_is_not_skinned = false;
+ bone_is_skinned = true;
break;
}
}
// create a bone even if there's no joint data for it (i.e. it has no influence)
- if (bone_is_not_skinned) {
- float obmat[4][4];
- // bone-space
- get_node_mat(obmat, node, NULL, NULL);
-
- // get world-space
- if (parent) {
- mul_m4_m4m4(mat, parent_mat, obmat);
- }
- else {
- copy_m4_m4(mat, obmat);
- }
+ if (!bone_is_skinned) {
+ get_node_mat(mat, node, NULL, NULL, parent_mat);
}
if (parent) bone->parent = parent;
@@ -156,10 +150,11 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
int use_connect = be.get_use_connect();
switch (use_connect) {
- case 1: bone->flag |= BONE_CONNECTED;
- break;
- case 0: bone->flag &= ~BONE_CONNECTED;
- case -1: break; // not defined
+ case 1: bone->flag |= BONE_CONNECTED;
+ break;
+ case -1:/* Connect type not specified */
+ case 0: bone->flag &= ~BONE_CONNECTED;
+ break;
}
if (be.has_roll()) {
@@ -169,8 +164,18 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
float angle;
mat4_to_loc_rot_size(loc, rot, size, mat);
mat3_to_vec_roll(rot, NULL, &angle);
+ bone->roll = angle;
}
copy_v3_v3(bone->head, mat[3]);
+
+ if (bone_is_skinned)
+ {
+ float rest_mat[4][4];
+ get_node_mat(rest_mat, node, NULL, NULL, NULL);
+ bc_set_IDPropertyMatrix(bone, "bind_mat", joint_bind_mat);
+ bc_set_IDPropertyMatrix(bone, "rest_mat", rest_mat);
+ }
+
add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero
/* find smallest bone length in armature (used later for leaf bone length) */
@@ -272,7 +277,6 @@ void ArmatureImporter::fix_parent_connect(bArmature *armature, Bone *bone)
}
-
void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone, int clip)
{
BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(armature);
@@ -288,12 +292,13 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
for (; child; child = child->next) {
BoneExtended *be = extended_bones[child->name];
if (be != NULL) {
- if (be->get_chain_length() <= clip) {
- if (be->get_chain_length() > maxlen) {
+ int chain_len = be->get_chain_length();
+ if (chain_len <= clip) {
+ if (chain_len > maxlen) {
dominant_child = be;
- maxlen = be->get_chain_length();
+ maxlen = chain_len;
}
- else if (be->get_chain_length() == maxlen) {
+ else if (chain_len == maxlen) {
dominant_child = NULL;
}
}
@@ -307,7 +312,6 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
EditBone *pebone = bc_get_edit_bone(armature, parentbone->name);
EditBone *cebone = bc_get_edit_bone(armature, dominant_child->get_name());
if (pebone && !(cebone->flag & BONE_CONNECTED)) {
-
float vec[3];
sub_v3_v3v3(vec, cebone->head, pebone->head);
@@ -320,14 +324,16 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
if (len_squared_v3(vec) > MINIMUM_BONE_LENGTH)
{
- pebone->tail[0] = cebone->head[0];
- pebone->tail[1] = cebone->head[1];
- pebone->tail[2] = cebone->head[2];
-
+ copy_v3_v3(pebone->tail, cebone->head);
+ pbe->set_tail(pebone->tail); /* to make fix_leafbone happy ...*/
if (pbe && pbe->get_chain_length() >= this->import_settings->min_chain_length) {
+
+ BoneExtended *cbe = extended_bones[cebone->name];
+ cbe->set_use_connect(true);
+
cebone->flag |= BONE_CONNECTED;
- printf("Connecting chain: parent %s --> %s (child)\n", pebone->name, cebone->name);
pbe->set_leaf_bone(false);
+ printf("Connect Bone chain: parent (%s --> %s) child)\n", pebone->name, cebone->name);
}
}
}
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index 06e151c363b..5cd5e6d271a 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -98,7 +98,10 @@ bool ControllerExporter::add_instance_controller(Object *ob)
write_bone_URLs(ins, ob_arm, bone);
}
- InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only);
+ InstanceWriter::add_material_bindings(ins.getBindMaterial(),
+ ob,
+ this->export_settings->active_uv_only,
+ this->export_settings->export_texture_type);
ins.add();
return true;
@@ -157,11 +160,6 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O
}
#endif
-std::string ControllerExporter::get_joint_sid(Bone *bone, Object *ob_arm)
-{
- return get_joint_id(bone, ob_arm);
-}
-
std::string ControllerExporter::get_controller_id(Object *ob_arm, Object *ob)
{
return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) + SKIN_CONTROLLER_ID_SUFFIX;
@@ -468,81 +466,6 @@ std::string ControllerExporter::add_joints_source(Object *ob_arm, ListBase *defb
return source_id;
}
-static float get_property(Bone *bone, const char *key, float def)
-{
- float result = def;
- if (bone->prop) {
- IDProperty *property = IDP_GetPropertyFromGroup(bone->prop, key);
- if (property) {
- switch (property->type) {
- case IDP_INT:
- result = (float)(IDP_Int(property));
- break;
- case IDP_FLOAT:
- result = (float)(IDP_Float(property));
- break;
- case IDP_DOUBLE:
- result = (float)(IDP_Double(property));
- break;
- default:
- result = def;
- }
- }
- }
- return result;
-}
-
-/**
- * This function creates an arbitrary rest pose matrix from
- * data provided as custom properties. This is a workaround
- * for support of maya's restpose matrix which can be arbitrary
- * in opposition to Blender where the Rest pose Matrix is always
- * the Identity matrix.
- *
- * The custom properties are:
- *
- * restpose_scale_x
- * restpose_scale_y
- * restpose_scale_z
- *
- * restpose_rot_x
- * restpose_rot_y
- * restpose_rot_z
- *
- * restpose_loc_x
- * restpose_loc_y
- * restpose_loc_z
- *
- * The matrix is only setup if the scale AND the rot properties are defined.
- * The presence of the loc properties is optional.
- *
- * This feature has been implemented to support Second Life "Fitted Mesh"
- * TODO: Check if an arbitrary rest pose matrix makes sense within Blender.
- * Eventually leverage the custom property data into an "official"
- * Edit_bone Property
- */
-static void create_restpose_mat(Bone *bone, float mat[4][4])
-{
- float loc[3] = {
- get_property(bone, "restpose_loc_x", 0.0),
- get_property(bone, "restpose_loc_y", 0.0),
- get_property(bone, "restpose_loc_z", 0.0)
- };
-
- float rot[3] = {
- DEG2RADF(get_property(bone, "restpose_rot_x", 0.0)),
- DEG2RADF(get_property(bone, "restpose_rot_y", 0.0)),
- DEG2RADF(get_property(bone, "restpose_rot_z", 0.0))
- };
-
- float scale[3] = {
- get_property(bone, "restpose_scale_x", 1.0),
- get_property(bone, "restpose_scale_y", 1.0),
- get_property(bone, "restpose_scale_z", 1.0)
- };
-
- loc_eulO_size_to_mat4(mat, loc, rot, scale, 6);
-}
std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
{
@@ -585,30 +508,36 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas
float world[4][4];
float inv_bind_mat[4][4];
+ float bind_mat[4][4]; /* derived from bone->arm_mat */
+
+ bool has_bindmat = bc_get_property_matrix(pchan->bone, "bind_mat", bind_mat);
- // SL/OPEN_SIM COMPATIBILITY
- if (export_settings->open_sim) {
- // Only translations, no rotation vs armature
- float temp[4][4];
- unit_m4(temp);
- copy_v3_v3(temp[3], pchan->bone->arm_mat[3]);
- mul_m4_m4m4(world, ob_arm->obmat, temp);
-
- // Add Maya restpose matrix (if defined as properties)
- float restpose_mat[4][4];
- create_restpose_mat(pchan->bone, restpose_mat);
- mul_m4_m4m4(world, world, restpose_mat);
+ if (!has_bindmat) {
- }
- else {
- // make world-space matrix, arm_mat is armature-space
- mul_m4_m4m4(world, ob_arm->obmat, pchan->bone->arm_mat);
+ /* Have no bind matrix stored, try old style <= Blender 2.78 */
+
+ bc_create_restpose_mat(this->export_settings, pchan->bone, bind_mat, pchan->bone->arm_mat, true);
+
+ // SL/OPEN_SIM COMPATIBILITY
+ if (export_settings->open_sim) {
+
+ float loc[3];
+ float rot[3] = { 0, 0, 0 };
+ float scale[3];
+ bc_decompose(bind_mat, loc, NULL, NULL, scale);
+
+ // Only translations, no rotation vs armature
+ loc_eulO_size_to_mat4(bind_mat, loc, rot, scale, 6);
+ }
}
+ // make world-space matrix (bind_mat is armature-space)
+ mul_m4_m4m4(world, ob_arm->obmat, bind_mat);
invert_m4_m4(mat, world);
converter.mat4_to_dae(inv_bind_mat, mat);
-
+ if (this->export_settings->limit_precision)
+ bc_sanitize_mat(inv_bind_mat, 6);
source.appendValues(inv_bind_mat);
}
}
diff --git a/source/blender/collada/ControllerExporter.h b/source/blender/collada/ControllerExporter.h
index 0be51187f6f..80b858ca6dd 100644
--- a/source/blender/collada/ControllerExporter.h
+++ b/source/blender/collada/ControllerExporter.h
@@ -84,8 +84,6 @@ private:
void find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce);
#endif
- std::string get_joint_sid(Bone *bone, Object *ob_arm);
-
std::string get_controller_id(Object *ob_arm, Object *ob);
std::string get_controller_id(Key *key, Object *ob);
diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp
index bd32e989ae3..dcfd062470c 100644
--- a/source/blender/collada/DocumentExporter.cpp
+++ b/source/blender/collada/DocumentExporter.cpp
@@ -138,7 +138,8 @@ extern bool bc_has_object_type(LinkNode *export_set, short obtype);
char *bc_CustomData_get_layer_name(const struct CustomData *data, int type, int n)
{
int layer_index = CustomData_get_layer_index(data, type);
- if (layer_index < 0) return NULL;
+ if (layer_index < 0)
+ return NULL;
return data->layers[layer_index + n].name;
}
@@ -147,9 +148,10 @@ char *bc_CustomData_get_active_layer_name(const CustomData *data, int type)
{
/* get the layer index of the active layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
- if (layer_index < 0) return NULL;
+ if (layer_index < 1)
+ return NULL;
- return data->layers[layer_index].name;
+ return bc_CustomData_get_layer_name(data, type, layer_index-1);
}
DocumentExporter::DocumentExporter(const ExportSettings *export_settings) : export_settings(export_settings) {
@@ -303,7 +305,10 @@ int DocumentExporter::exportCurrentScene(Scene *sce)
// <library_visual_scenes>
SceneExporter se(writer, &arm_exporter, this->export_settings);
-
+#if 0
+ /* The following code seems to be an obsolete workaround
+ Comment out until it proofs correct that we no longer need it.
+ */
if (has_animations && this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) {
// channels adressing <matrix> objects is not (yet) supported
// So we force usage of <location>, <translation> and <scale>
@@ -315,7 +320,9 @@ int DocumentExporter::exportCurrentScene(Scene *sce)
else {
se.setExportTransformationType(this->export_settings->export_transformation_type);
}
-
+#else
+ se.setExportTransformationType(this->export_settings->export_transformation_type);
+#endif
se.exportScene(sce);
// <scene>
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 226f319cefd..f7fdfb06a40 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -388,9 +388,7 @@ Object *DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera
Camera *cam = uid_camera_map[cam_uid];
Camera *old_cam = (Camera *)ob->data;
ob->data = cam;
- id_us_min(&old_cam->id);
- if (old_cam->id.us == 0)
- BKE_libblock_free(G.main, old_cam);
+ BKE_libblock_free_us(G.main, old_cam);
return ob;
}
@@ -406,9 +404,7 @@ Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Sce
Lamp *la = uid_lamp_map[lamp_uid];
Lamp *old_lamp = (Lamp *)ob->data;
ob->data = la;
- id_us_min(&old_lamp->id);
- if (old_lamp->id.us == 0)
- BKE_libblock_free(G.main, old_lamp);
+ BKE_libblock_free_us(G.main, old_lamp);
return ob;
}
@@ -512,9 +508,9 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
std::vector<Object *> *root_objects = new std::vector<Object *>();
fprintf(stderr,
- "Writing node id='%s', name='%s'\n",
- id.c_str(),
- name.c_str());
+ "Writing node id='%s', name='%s'\n",
+ id.c_str(),
+ name.c_str());
if (is_joint) {
if (parent_node == NULL && !is_library_node) {
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index 76b51148509..2bf0859b0f0 100644
--- a/source/blender/collada/EffectExporter.cpp
+++ b/source/blender/collada/EffectExporter.cpp
@@ -27,7 +27,6 @@
#include <map>
-#include <set>
#include "COLLADASWEffectProfile.h"
#include "COLLADAFWColorOrTexture.h"
@@ -49,21 +48,10 @@ extern "C" {
#include "BKE_material.h"
}
-// OB_MESH is assumed
-static std::string getActiveUVLayerName(Object *ob)
-{
- Mesh *me = (Mesh *)ob->data;
-
- int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
- if (num_layers)
- return std::string(bc_CustomData_get_active_layer_name(&me->fdata, CD_MTFACE));
-
- return "";
-}
-
EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryEffects(sw), export_settings(export_settings) {
}
+
bool EffectsExporter::hasEffects(Scene *sce)
{
Base *base = (Base *)sce->base.first;
@@ -86,13 +74,49 @@ bool EffectsExporter::hasEffects(Scene *sce)
void EffectsExporter::exportEffects(Scene *sce)
{
- if (hasEffects(sce)) {
- this->scene = sce;
- openLibrary();
- MaterialFunctor mf;
- mf.forEachMaterialInExportSet<EffectsExporter>(sce, *this, this->export_settings->export_set);
-
- closeLibrary();
+ this->scene = sce;
+
+ if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT) {
+ if (hasEffects(sce)) {
+ MaterialFunctor mf;
+ openLibrary();
+ mf.forEachMaterialInExportSet<EffectsExporter>(sce, *this, this->export_settings->export_set);
+ closeLibrary();
+ }
+ }
+ else {
+ std::set<Object *> uv_textured_obs = bc_getUVTexturedObjects(sce, !this->export_settings->active_uv_only);
+ std::set<Image *> uv_images = bc_getUVImages(sce, !this->export_settings->active_uv_only);
+ if (uv_images.size() > 0) {
+ openLibrary();
+ std::set<Image *>::iterator uv_images_iter;
+ for (uv_images_iter = uv_images.begin();
+ uv_images_iter != uv_images.end();
+ uv_images_iter++) {
+
+ Image *ima = *uv_images_iter;
+ std::string key(id_name(ima));
+ key = translate_id(key);
+ COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
+ key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
+ key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
+ sampler.setImageId(key);
+
+ openEffect(key + "-effect");
+ COLLADASW::EffectProfile ep(mSW);
+ ep.setProfileType(COLLADASW::EffectProfile::COMMON);
+ ep.setShaderType(COLLADASW::EffectProfile::PHONG);
+ ep.setDiffuse(createTexture(ima, key, &sampler), false, "diffuse");
+ COLLADASW::ColorOrTexture cot = getcol(0, 0, 0, 1.0f);
+ ep.setSpecular(cot, false, "specular");
+ ep.openProfile();
+ ep.addProfileElements();
+ ep.addExtraTechniques(mSW);
+ ep.closeProfile();
+ closeEffect();
+ }
+ closeLibrary();
+ }
}
}
@@ -176,8 +200,7 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
{
// create a list of indices to textures of type TEX_IMAGE
std::vector<int> tex_indices;
- if (this->export_settings->include_material_textures)
- createTextureIndices(ma, tex_indices);
+ createTextureIndices(ma, tex_indices);
openEffect(translate_id(id_name(ma)) + "-effect");
@@ -311,61 +334,9 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
}
}
- int active_uv_layer = -1;
- std::set<Image *> uv_textures;
- if (ob->type == OB_MESH && ob->totcol && this->export_settings->include_uv_textures) {
- bool active_uv_only = this->export_settings->active_uv_only;
- Mesh *me = (Mesh *) ob->data;
- active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
-
- BKE_mesh_tessface_ensure(me);
- for (int i = 0; i < me->pdata.totlayer; i++) {
- if (!active_uv_only || active_uv_layer == i)
- {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
- MPoly *mpoly = me->mpoly;
- for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) {
-
- Material *mat = give_current_material(ob, mpoly->mat_nr + 1);
- if (mat != ma)
- continue;
-
- Image *ima = txface->tpage;
- if (ima == NULL)
- continue;
-
-
- bool not_in_list = uv_textures.find(ima)==uv_textures.end();
- if (not_in_list) {
- std::string name = id_name(ima);
- std::string key(name);
- key = translate_id(key);
-
- // create only one <sampler>/<surface> pair for each unique image
- if (im_samp_map.find(key) == im_samp_map.end()) {
- //<newparam> <sampler> <source>
- COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
- key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
- key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
- sampler.setImageId(key);
- samplers[a] = sampler;
- samp_surf[b] = &samplers[a];
- im_samp_map[key] = b;
- b++;
- a++;
- uv_textures.insert(ima);
- }
- }
- }
- }
- }
- }
- }
-
// used as fallback when MTex->uvname is "" (this is pretty common)
// it is indeed the correct value to use in that case
- std::string active_uv(getActiveUVLayerName(ob));
+ std::string active_uv(bc_get_active_uvlayer_name(ob));
// write textures
// XXX very slow
@@ -385,19 +356,6 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
writeTextures(ep, key, sampler, t, ima, uvname);
}
- std::set<Image *>::iterator uv_t_iter;
- int idx;
- for (idx = 0, uv_t_iter = uv_textures.begin(); uv_t_iter != uv_textures.end(); uv_t_iter++, idx++ ) {
- if (active_uv_layer>-1 && idx==active_uv_layer) {
- Image *ima = *uv_t_iter;
- std::string key(id_name(ima));
- key = translate_id(key);
- int i = im_samp_map[key];
- COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i];
- ep.setDiffuse(createTexture(ima, active_uv, sampler), false, "diffuse");
- }
- }
-
// performs the actual writing
ep.addProfileElements();
bool twoSided = false;
diff --git a/source/blender/collada/EffectExporter.h b/source/blender/collada/EffectExporter.h
index d20cbfdfe0b..7d45a085777 100644
--- a/source/blender/collada/EffectExporter.h
+++ b/source/blender/collada/EffectExporter.h
@@ -48,7 +48,6 @@ class EffectsExporter: COLLADASW::LibraryEffects
public:
EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
void exportEffects(Scene *sce);
-
void operator()(Material *ma, Object *ob);
COLLADASW::ColorOrTexture createTexture(Image *ima,
diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp
index 98aa85f8a9b..32aa5636e08 100644
--- a/source/blender/collada/ErrorHandler.cpp
+++ b/source/blender/collada/ErrorHandler.cpp
@@ -49,7 +49,7 @@ ErrorHandler::~ErrorHandler()
//--------------------------------------------------------------------
bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
{
- bool isError = true;
+ bool isError = false;
if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXPARSER) {
COLLADASaxFWL::SaxParserError *saxParserError = (COLLADASaxFWL::SaxParserError *) error;
@@ -81,10 +81,7 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
* Accept non critical errors as warnings (i.e. texture not found)
* This makes the importer more graceful, so it now imports what makes sense.
*/
- if (saxFWLError->getSeverity() == COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL) {
- isError = false;
- }
-
+ isError = (saxFWLError->getSeverity() != COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL);
std::cout << "Sax FWL Error: " << saxFWLError->getErrorMessage() << std::endl;
}
else {
@@ -93,5 +90,5 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
mError |= isError;
- return false; // let OpenCollada decide when to abort
+ return isError; // let OpenCollada decide when to abort
}
diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h
index 9451cac9dae..6d90edd2f67 100644
--- a/source/blender/collada/ExportSettings.h
+++ b/source/blender/collada/ExportSettings.h
@@ -28,7 +28,6 @@
#define __EXPORTSETTINGS_H__
#include "collada.h"
-#include "collada.h"
struct ExportSettings {
public:
@@ -42,8 +41,7 @@ public:
bool deform_bones_only;
bool active_uv_only;
- bool include_uv_textures;
- bool include_material_textures;
+ BC_export_texture_type export_texture_type;
bool use_texture_copies;
bool triangulate;
@@ -51,7 +49,10 @@ public:
bool use_blender_profile;
bool sort_by_name;
BC_export_transformation_type export_transformation_type;
+
bool open_sim;
+ bool limit_precision;
+ bool keep_bind_info;
char *filepath;
LinkNode *export_set;
diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp
index 7c7c57f3305..8a9ccbbed51 100644
--- a/source/blender/collada/GeometryExporter.cpp
+++ b/source/blender/collada/GeometryExporter.cpp
@@ -52,6 +52,7 @@ extern "C" {
#include "collada_internal.h"
#include "collada_utils.h"
+
// TODO: optimize UV sets by making indexed list with duplicates removed
GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryGeometries(sw), export_settings(export_settings)
{
@@ -134,13 +135,22 @@ void GeometryExporter::operator()(Object *ob)
// Only create Polylists if number of faces > 0
if (me->totface > 0) {
// XXX slow
- if (ob->totcol) {
- for (int a = 0; a < ob->totcol; a++) {
- createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
+ std::set<Image *> uv_images = bc_getUVImages(ob, !this->export_settings->active_uv_only);
+ if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT || uv_images.size() == 0) {
+ if (ob->totcol) {
+ for (int a = 0; a < ob->totcol; a++) {
+ createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
+ }
+ }
+ else {
+ int i = 0;
+ createPolylist(i, has_uvs, has_color, ob, me, geom_id, norind);
}
}
else {
- createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
+ bool all_uv_layers = !this->export_settings->active_uv_only;
+ std::set<Image *> uv_images = bc_getUVImages(ob, all_uv_layers);
+ createPolylists(uv_images, has_uvs, has_color, ob, me, geom_id, norind);
}
}
@@ -220,13 +230,15 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
//createLooseEdgeList(ob, me, geom_id, norind);
// XXX slow
- if (ob->totcol) {
+ if (ob->totcol && this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT) {
for (int a = 0; a < ob->totcol; a++) {
createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
}
}
else {
- createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
+ bool all_uv_layers = !this->export_settings->active_uv_only;
+ std::set<Image *> uv_images = bc_getUVImages(ob, all_uv_layers);
+ createPolylists(uv_images, has_uvs, has_color, ob, me, geom_id, norind);
}
closeMesh();
@@ -295,7 +307,44 @@ std::string GeometryExporter::makeVertexColorSourceId(std::string& geom_id, char
return result;
}
-// powerful because it handles both cases when there is material and when there's not
+static void prepareToAppendValues(bool is_triangulated, COLLADASW::PrimitivesBase *facelist, std::vector<unsigned long> &vcount_list)
+{
+ // performs the actual writing
+ if (is_triangulated) {
+ ((COLLADASW::Triangles *)facelist)->prepareToAppendValues();
+ }
+ else {
+ // sets <vcount>
+ facelist->setVCountList(vcount_list);
+ ((COLLADASW::Polylist *)facelist)-> prepareToAppendValues();
+ }
+}
+
+static void finishList(bool is_triangulated, COLLADASW::PrimitivesBase *facelist)
+{
+ if (is_triangulated) {
+ ((COLLADASW::Triangles *)facelist)->finish();
+ }
+ else {
+ ((COLLADASW::Polylist *)facelist)->finish();
+ }
+}
+
+COLLADASW::PrimitivesBase *getFacelist(bool is_triangulated, COLLADASW::StreamWriter *mSW)
+{
+ COLLADASW::PrimitivesBase *facelist;
+
+ if (is_triangulated)
+ {
+ facelist = new COLLADASW::Triangles(mSW);
+ }
+ else {
+ facelist = new COLLADASW::Polylist(mSW);
+ }
+ return facelist;
+}
+
+// Export meshes with Materials
void GeometryExporter::createPolylist(short material_index,
bool has_uvs,
bool has_color,
@@ -313,7 +362,7 @@ void GeometryExporter::createPolylist(short material_index,
int i;
int faces_in_polylist = 0;
std::vector<unsigned long> vcount_list;
-
+ bool is_triangulated = true;
// count faces with this material
for (i = 0; i < totpolys; i++) {
MPoly *p = &mpolys[i];
@@ -321,6 +370,9 @@ void GeometryExporter::createPolylist(short material_index,
if (p->mat_nr == material_index) {
faces_in_polylist++;
vcount_list.push_back(p->totloop);
+ if (p->totloop != 3) {
+ is_triangulated = false;
+ }
}
}
@@ -331,20 +383,21 @@ void GeometryExporter::createPolylist(short material_index,
}
Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
- COLLADASW::Polylist polylist(mSW);
+ COLLADASW::PrimitivesBase *facelist = getFacelist(is_triangulated, mSW);
+
// sets count attribute in <polylist>
- polylist.setCount(faces_in_polylist);
+ facelist->setCount(faces_in_polylist);
// sets material name
if (ma) {
std::string material_id = get_material_id(ma);
std::ostringstream ostr;
ostr << translate_id(material_id);
- polylist.setMaterial(ostr.str());
+ facelist->setMaterial(ostr.str());
}
-
- COLLADASW::InputList &til = polylist.getInputList();
+
+ COLLADASW::InputList &til = facelist->getInputList();
// creates <input> in <polylist> for vertices
COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
@@ -360,13 +413,21 @@ void GeometryExporter::createPolylist(short material_index,
int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1;
for (i = 0; i < num_layers; i++) {
if (!this->export_settings->active_uv_only || i == active_uv_index) {
-
- // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
+
+ std::string uv_name(bc_get_uvlayer_name(me, i));
+ std::string effective_id = geom_id; // (uv_name == "") ? geom_id : uv_name;
+ std::string layer_id = makeTexcoordSourceId(
+ effective_id,
+ i, this->export_settings->active_uv_only);
+
+ /* Note: the third parameter denotes the offset of TEXCOORD in polylist elements
+ For now this is always 2 (This may change sometime/maybe)
+ */
COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
- makeUrl(makeTexcoordSourceId(geom_id, i, this->export_settings->active_uv_only)),
- 2, // this is only until we have optimized UV sets
- (this->export_settings->active_uv_only) ? 0 : i // only_active_uv exported -> we have only one set
- );
+ makeUrl(layer_id),
+ 2, // this is only until we have optimized UV sets
+ (this->export_settings->active_uv_only) ? 0 : i // only_active_uv exported -> we have only one set
+ );
til.push_back(input3);
}
}
@@ -387,12 +448,10 @@ void GeometryExporter::createPolylist(short material_index,
}
}
- // sets <vcount>
- polylist.setVCountList(vcount_list);
// performs the actual writing
- polylist.prepareToAppendValues();
-
+ prepareToAppendValues(is_triangulated, facelist, vcount_list);
+
// <p>
int texindex = 0;
for (i = 0; i < totpolys; i++) {
@@ -404,22 +463,202 @@ void GeometryExporter::createPolylist(short material_index,
BCPolygonNormalsIndices normal_indices = norind[i];
for (int j = 0; j < loop_count; j++) {
- polylist.appendValues(l[j].v);
- polylist.appendValues(normal_indices[j]);
+ facelist->appendValues(l[j].v);
+ facelist->appendValues(normal_indices[j]);
if (has_uvs)
- polylist.appendValues(texindex + j);
+ facelist->appendValues(texindex + j);
if (has_color)
- polylist.appendValues(texindex + j);
+ facelist->appendValues(texindex + j);
}
}
texindex += loop_count;
}
-
- polylist.finish();
+
+ finishList(is_triangulated, facelist);
+ delete facelist;
}
+void GeometryExporter::createPolylists(std::set<Image *> uv_images,
+ bool has_uvs,
+ bool has_color,
+ Object *ob,
+ Mesh *me,
+ std::string& geom_id,
+ std::vector<BCPolygonNormalsIndices>& norind)
+{
+ std::set<Image *>::iterator uv_images_iter;
+ for (uv_images_iter = uv_images.begin();
+ uv_images_iter != uv_images.end();
+ uv_images_iter++) {
+
+ Image *ima = *uv_images_iter;
+ std::string imageid(id_name(ima));
+ createPolylist(imageid, has_uvs,
+ has_color,
+ ob,
+ me,
+ geom_id,
+ norind);
+ }
+
+ /* We msut add an additional collector for the case when
+ * some parts of the object are not textured at all.
+ * The next call creates a polylist for all untextured polygons
+ */
+
+ createPolylist("", has_uvs,
+ has_color,
+ ob,
+ me,
+ geom_id,
+ norind);
+
+}
+
+/* ===========================================================================
+ * Export Meshes with UV Textures (export as materials, see also in
+ * effectExporter and MaterialExporter)
+ *
+ * If imageid is the empty string, then collect only untextured polygons
+ * =========================================================================== */
+void GeometryExporter::createPolylist(std::string imageid,
+ bool has_uvs,
+ bool has_color,
+ Object *ob,
+ Mesh *me,
+ std::string& geom_id,
+ std::vector<BCPolygonNormalsIndices>& norind)
+{
+
+ MPoly *mpolys = me->mpoly;
+ MLoop *mloops = me->mloop;
+ MTexPoly *mtpolys = me->mtpoly;
+
+ int totpolys = me->totpoly;
+
+ // <vcount>
+ int i;
+ int faces_in_polylist = 0;
+ std::vector<unsigned long> vcount_list;
+ bool is_triangulated = true;
+ // count faces with this material
+ for (i = 0; i < totpolys; i++) {
+ MTexPoly *tp = &mtpolys[i];
+ MPoly *p = &mpolys[i];
+
+ std::string tpageid = (tp->tpage) ? id_name(tp->tpage):"";
+ if (tpageid == imageid) {
+ faces_in_polylist++;
+ vcount_list.push_back(p->totloop);
+ if (p->totloop != 3) {
+ is_triangulated = false;
+ }
+ }
+ }
+
+ // no faces using this imageid
+ if (faces_in_polylist == 0) {
+ if (imageid != "")
+ fprintf(stderr, "%s: Image %s is not used.\n", id_name(ob).c_str(), imageid.c_str());
+ return;
+ }
+
+ COLLADASW::PrimitivesBase *facelist = getFacelist(is_triangulated, mSW);
+
+ // sets count attribute in <polylist>
+ facelist->setCount(faces_in_polylist);
+
+ if (imageid != "") {
+ // sets material name
+ std::string material_id = get_material_id_from_id(imageid);
+ std::ostringstream ostr;
+ ostr << translate_id(material_id);
+ facelist->setMaterial(ostr.str());
+ }
+ COLLADASW::InputList &til = facelist->getInputList();
+
+ // creates <input> in <polylist> for vertices
+ COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
+
+ // creates <input> in <polylist> for normals
+ COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
+
+ til.push_back(input1);
+ til.push_back(input2);
+
+ // if mesh has uv coords writes <input> for TEXCOORD
+ int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) - 1;
+ for (i = 0; i < num_layers; i++) {
+ if (!this->export_settings->active_uv_only || i == active_uv_index) {
+
+ std::string uv_name(bc_get_uvlayer_name(me, i));
+ std::string effective_id = geom_id; // (uv_name == "") ? geom_id : uv_name;
+ std::string layer_id = makeTexcoordSourceId(
+ effective_id,
+ i, this->export_settings->active_uv_only);
+
+ /* Note: the third parameter denotes the offset of TEXCOORD in polylist elements
+ For now this is always 2 (This may change sometime/maybe)
+ */
+ COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
+ makeUrl(layer_id),
+ 2, // this is only until we have optimized UV sets
+ (this->export_settings->active_uv_only) ? 0 : i // only_active_uv exported -> we have only one set
+ );
+ til.push_back(input3);
+ }
+ }
+
+ int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
+ if (totlayer_mcol > 0) {
+ int map_index = 0;
+
+ for (int a = 0; a < totlayer_mcol; a++) {
+ char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
+ COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR,
+ makeUrl(makeVertexColorSourceId(geom_id, layer_name)),
+ (has_uvs) ? 3 : 2, // all color layers have same index order
+ map_index // set number equals color map index
+ );
+ til.push_back(input4);
+ map_index++;
+ }
+ }
+
+ // performs the actual writing
+ prepareToAppendValues(is_triangulated, facelist, vcount_list);
+
+ // <p>
+ int texindex = 0;
+ for (i = 0; i < totpolys; i++) {
+ MTexPoly *tp = &mtpolys[i];
+ MPoly *p = &mpolys[i];
+ int loop_count = p->totloop;
+ std::string tpageid = (tp->tpage) ? id_name(tp->tpage) : "";
+ if (tpageid == imageid) {
+ MLoop *l = &mloops[p->loopstart];
+ BCPolygonNormalsIndices normal_indices = norind[i];
+
+ for (int j = 0; j < loop_count; j++) {
+ facelist->appendValues(l[j].v);
+ facelist->appendValues(normal_indices[j]);
+ if (has_uvs)
+ facelist->appendValues(texindex + j);
+
+ if (has_color)
+ facelist->appendValues(texindex + j);
+ }
+ }
+
+ texindex += loop_count;
+ }
+
+ finishList(is_triangulated, facelist);
+ delete facelist;
+}
// creates <source> for positions
void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
@@ -479,12 +718,13 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(me->totloop);
- source.setAccessorStride(3);
+ source.setAccessorStride(4);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("R");
param.push_back("G");
param.push_back("B");
+ param.push_back("A");
source.prepareToAppendValues();
@@ -496,7 +736,8 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
source.appendValues(
mlc->r / 255.0f,
mlc->g / 255.0f,
- mlc->b / 255.0f
+ mlc->b / 255.0f,
+ mlc->a / 255.0f
);
}
}
@@ -537,7 +778,13 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a);
COLLADASW::FloatSourceF source(mSW);
- std::string layer_id = makeTexcoordSourceId(geom_id, a, this->export_settings->active_uv_only);
+ std::string active_uv_name(bc_get_active_uvlayer_name(me));
+ std::string effective_id = geom_id; // (active_uv_name == "") ? geom_id : active_uv_name;
+ std::string layer_id = makeTexcoordSourceId(
+ effective_id,
+ a,
+ this->export_settings->active_uv_only );
+
source.setId(layer_id);
source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
diff --git a/source/blender/collada/GeometryExporter.h b/source/blender/collada/GeometryExporter.h
index 69d1067e6f4..890304f4568 100644
--- a/source/blender/collada/GeometryExporter.h
+++ b/source/blender/collada/GeometryExporter.h
@@ -85,15 +85,33 @@ public:
Mesh *me,
std::string& geom_id);
- // powerful because it handles both cases when there is material and when there's not
+ // Create polylists for meshes with Materials
void createPolylist(short material_index,
- bool has_uvs,
- bool has_color,
- Object *ob,
- Mesh *me,
- std::string& geom_id,
- std::vector<BCPolygonNormalsIndices>& norind);
-
+ bool has_uvs,
+ bool has_color,
+ Object *ob,
+ Mesh *me,
+ std::string& geom_id,
+ std::vector<BCPolygonNormalsIndices>& norind);
+
+ // Create polylists for meshes with UV Textures
+ void createPolylists(std::set<Image *> uv_images,
+ bool has_uvs,
+ bool has_color,
+ Object *ob,
+ Mesh *me,
+ std::string& geom_id,
+ std::vector<BCPolygonNormalsIndices>& norind);
+
+ // Create polylists for meshes with UV Textures
+ void createPolylist(std::string imageid,
+ bool has_uvs,
+ bool has_color,
+ Object *ob,
+ Mesh *me,
+ std::string& geom_id,
+ std::vector<BCPolygonNormalsIndices>& norind);
+
// creates <source> for positions
void createVertsSource(std::string geom_id, Mesh *me);
diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp
index aac41e2e93c..93be7de6236 100644
--- a/source/blender/collada/ImageExporter.cpp
+++ b/source/blender/collada/ImageExporter.cpp
@@ -55,9 +55,9 @@ ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings
void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
{
- std::string name(id_name(image));
- std::string translated_name(translate_id(name));
- bool not_yet_exported = find(mImages.begin(), mImages.end(), translated_name) == mImages.end();
+ std::string id(id_name(image));
+ std::string translated_id(translate_id(id));
+ bool not_yet_exported = find(mImages.begin(), mImages.end(), translated_id) == mImages.end();
if (not_yet_exported) {
@@ -88,7 +88,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
// make absolute destination path
- BLI_strncpy(export_file, name.c_str(), sizeof(export_file));
+ BLI_strncpy(export_file, id.c_str(), sizeof(export_file));
BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat);
BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file);
@@ -143,10 +143,11 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
}
}
- COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)), translated_name, translated_name); /* set name also to mNameNC. This helps other viewers import files exported from Blender better */
+ /* set name also to mNameNC. This helps other viewers import files exported from Blender better */
+ COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)), translated_id, translated_id);
img.add(mSW);
fprintf(stdout, "Collada export: Added image: %s\n", export_file);
- mImages.push_back(translated_name);
+ mImages.push_back(translated_id);
BKE_image_release_ibuf(image, imbuf, NULL);
}
@@ -161,7 +162,7 @@ void ImagesExporter::export_UV_Images()
for (node = this->export_settings->export_set; node; node = node->next) {
Object *ob = (Object *)node->link;
- if (ob->type == OB_MESH && ob->totcol) {
+ if (ob->type == OB_MESH) {
Mesh *me = (Mesh *) ob->data;
BKE_mesh_tessface_ensure(me);
int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
@@ -189,7 +190,13 @@ void ImagesExporter::export_UV_Images()
}
}
-
+/* ============================================================
+ * Check if there are any images to be exported
+ * Returns true as soon as an object is detected that
+ * either has an UV Texture assigned, or has a material
+ * assigned that uses an Image Texture.
+ * ============================================================
+ */
bool ImagesExporter::hasImages(Scene *sce)
{
LinkNode *node;
@@ -232,11 +239,10 @@ void ImagesExporter::exportImages(Scene *sce)
openLibrary();
MaterialFunctor mf;
- if (this->export_settings->include_material_textures) {
+ if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT) {
mf.forEachMaterialInExportSet<ImagesExporter>(sce, *this, this->export_settings->export_set);
}
-
- if (this->export_settings->include_uv_textures) {
+ else {
export_UV_Images();
}
diff --git a/source/blender/collada/ImportSettings.h b/source/blender/collada/ImportSettings.h
index 2c52d73e756..4a2d4e8046a 100644
--- a/source/blender/collada/ImportSettings.h
+++ b/source/blender/collada/ImportSettings.h
@@ -37,6 +37,7 @@ public:
bool fix_orientation;
int min_chain_length;
char *filepath;
+ bool keep_bind_info;
};
#endif
diff --git a/source/blender/collada/InstanceWriter.cpp b/source/blender/collada/InstanceWriter.cpp
index 71371d280df..de1a4075462 100644
--- a/source/blender/collada/InstanceWriter.cpp
+++ b/source/blender/collada/InstanceWriter.cpp
@@ -32,43 +32,76 @@
#include "COLLADASWInstanceMaterial.h"
extern "C" {
- #include "BKE_customdata.h"
- #include "BKE_material.h"
- #include "DNA_mesh_types.h"
+#include "BKE_customdata.h"
+#include "BKE_material.h"
+#include "DNA_mesh_types.h"
}
#include "InstanceWriter.h"
#include "collada_internal.h"
#include "collada_utils.h"
-void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only)
+void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only, BC_export_texture_type export_texture_type)
{
- for (int a = 0; a < ob->totcol; a++) {
- Material *ma = give_current_material(ob, a + 1);
-
- COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList();
+ bool all_uv_layers = !active_uv_only;
+ COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList();
- if (ma) {
- std::string matid(get_material_id(ma));
- matid = translate_id(matid);
+ if (export_texture_type == BC_TEXTURE_TYPE_UV)
+ {
+ std::set<Image *> uv_images = bc_getUVImages(ob, all_uv_layers);
+ std::set<Image *>::iterator uv_images_iter;
+ for (uv_images_iter = uv_images.begin();
+ uv_images_iter != uv_images.end();
+ uv_images_iter++) {
+ Image *ima = *uv_images_iter;
+ std::string matid(id_name(ima));
+ matid = get_material_id_from_id(matid);
std::ostringstream ostr;
ostr << matid;
COLLADASW::InstanceMaterial im(ostr.str(), COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid));
-
+
// create <bind_vertex_input> for each uv map
Mesh *me = (Mesh *)ob->data;
int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
-
+
int map_index = 0;
- int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) -1;
+ int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) - 1;
for (int b = 0; b < totlayer; b++) {
if (!active_uv_only || b == active_uv_index) {
char *name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, b);
im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", map_index++));
}
}
-
+
iml.push_back(im);
}
}
+
+ else {
+ for (int a = 0; a < ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a + 1);
+ if (ma) {
+ std::string matid(get_material_id(ma));
+ matid = translate_id(matid);
+ std::ostringstream ostr;
+ ostr << matid;
+ COLLADASW::InstanceMaterial im(ostr.str(), COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid));
+
+ // create <bind_vertex_input> for each uv map
+ Mesh *me = (Mesh *)ob->data;
+ int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+
+ int map_index = 0;
+ int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) - 1;
+ for (int b = 0; b < totlayer; b++) {
+ if (!active_uv_only || b == active_uv_index) {
+ char *name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, b);
+ im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", map_index++));
+ }
+ }
+
+ iml.push_back(im);
+ }
+ }
+ }
}
diff --git a/source/blender/collada/InstanceWriter.h b/source/blender/collada/InstanceWriter.h
index 49ddf091b1c..a46027325a2 100644
--- a/source/blender/collada/InstanceWriter.h
+++ b/source/blender/collada/InstanceWriter.h
@@ -31,11 +31,12 @@
#include "COLLADASWBindMaterial.h"
#include "DNA_object_types.h"
+#include "collada.h"
class InstanceWriter
{
protected:
- void add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only);
+ void add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only, BC_export_texture_type export_texture_type);
};
#endif
diff --git a/source/blender/collada/MaterialExporter.cpp b/source/blender/collada/MaterialExporter.cpp
index 4aece997f72..6e6cc24be20 100644
--- a/source/blender/collada/MaterialExporter.cpp
+++ b/source/blender/collada/MaterialExporter.cpp
@@ -38,14 +38,39 @@ MaterialsExporter::MaterialsExporter(COLLADASW::StreamWriter *sw, const ExportSe
void MaterialsExporter::exportMaterials(Scene *sce)
{
- if (hasMaterials(sce)) {
- openLibrary();
+ if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT)
+ {
+ if (hasMaterials(sce)) {
+ openLibrary();
- MaterialFunctor mf;
- mf.forEachMaterialInExportSet<MaterialsExporter>(sce, *this, this->export_settings->export_set);
+ MaterialFunctor mf;
+ mf.forEachMaterialInExportSet<MaterialsExporter>(sce, *this, this->export_settings->export_set);
- closeLibrary();
+ closeLibrary();
+ }
}
+
+ else {
+ std::set<Image *> uv_images = bc_getUVImages(sce, !this->export_settings->active_uv_only);
+ if (uv_images.size() > 0) {
+ openLibrary();
+ std::set<Image *>::iterator uv_images_iter;
+ for (uv_images_iter = uv_images.begin();
+ uv_images_iter != uv_images.end();
+ uv_images_iter++) {
+
+ Image *ima = *uv_images_iter;
+ std::string matid(id_name(ima));
+
+ openMaterial(get_material_id_from_id(matid), translate_id(matid));
+ std::string efid = translate_id(matid) + "-effect";
+ addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid));
+ closeMaterial();
+ }
+ closeLibrary();
+ }
+ }
+
}
bool MaterialsExporter::hasMaterials(Scene *sce)
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 8f3bf88af65..6ca53c64299 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -27,7 +27,7 @@
#include <algorithm>
-#if !defined(WIN32) || defined(FREE_WINDOWS)
+#if !defined(WIN32)
#include <iostream>
#endif
@@ -1173,8 +1173,9 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
BKE_mesh_assign_object(ob, new_mesh);
BKE_mesh_calc_normals(new_mesh);
- if (old_mesh->id.us == 0) BKE_libblock_free(G.main, old_mesh);
-
+ id_us_plus(&old_mesh->id); /* Because BKE_mesh_assign_object would have already decreased it... */
+ BKE_libblock_free_us(G.main, old_mesh);
+
char layername[100];
layername[0] = '\0';
MTFace *texture_face = NULL;
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index 30cd6ddf197..73945539931 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -151,7 +151,10 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
COLLADASW::InstanceGeometry instGeom(mSW);
instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, this->export_settings->use_object_instantiation)));
instGeom.setName(translate_id(id_name(ob)));
- InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob, this->export_settings->active_uv_only);
+ InstanceWriter::add_material_bindings(instGeom.getBindMaterial(),
+ ob,
+ this->export_settings->active_uv_only,
+ this->export_settings->export_texture_type);
instGeom.add();
}
diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp
index 7242a24523c..c48c060dc95 100644
--- a/source/blender/collada/SkinInfo.cpp
+++ b/source/blender/collada/SkinInfo.cpp
@@ -27,7 +27,7 @@
#include <algorithm>
-#if !defined(WIN32) || defined(FREE_WINDOWS)
+#if !defined(WIN32)
#include <stdint.h>
#endif
@@ -230,7 +230,6 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::Unique
ModifierData *md = ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Armature);
ArmatureModifierData *amd = (ArmatureModifierData *)md;
amd->object = ob_arm;
- struct bArmature *armature = (bArmature *)ob_arm->data;
#if 1
bc_set_parent(ob, ob_arm, C);
diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp
index f8f31304d28..7f742be7e30 100644
--- a/source/blender/collada/TransformReader.cpp
+++ b/source/blender/collada/TransformReader.cpp
@@ -34,7 +34,21 @@ TransformReader::TransformReader(UnitConverter *conv) : unit_converter(conv)
/* pass */
}
-void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob)
+void TransformReader::get_node_mat(
+ float mat[4][4],
+ COLLADAFW::Node *node,
+ std::map<COLLADAFW::UniqueId, Animation> *animation_map,
+ Object *ob)
+{
+ get_node_mat(mat, node, animation_map, ob, NULL);
+}
+
+void TransformReader::get_node_mat(
+ float mat[4][4],
+ COLLADAFW::Node *node,
+ std::map<COLLADAFW::UniqueId, Animation> *animation_map,
+ Object *ob,
+ float parent_mat[4][4])
{
float cur[4][4];
float copy[4][4];
@@ -52,6 +66,9 @@ void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::
// then this is considered as redundant information.
// So if we find a Matrix we use that and return.
dae_matrix_to_mat4(tm, mat);
+ if (parent_mat) {
+ mul_m4_m4m4(mat, parent_mat, mat);
+ }
return;
case COLLADAFW::Transformation::TRANSLATE:
dae_translate_to_mat4(tm, cur);
@@ -80,6 +97,10 @@ void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::
(*animation_map)[anim_list_id] = anim;
}
}
+
+ if (parent_mat) {
+ mul_m4_m4m4(mat, parent_mat, mat);
+ }
}
void TransformReader::dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4])
diff --git a/source/blender/collada/TransformReader.h b/source/blender/collada/TransformReader.h
index ab974b9ba85..08bb17ccac1 100644
--- a/source/blender/collada/TransformReader.h
+++ b/source/blender/collada/TransformReader.h
@@ -43,7 +43,7 @@
//struct Object;
-class TransformReader : public TransformBase
+class TransformReader
{
protected:
@@ -59,7 +59,8 @@ public:
TransformReader(UnitConverter *conv);
void get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob);
-
+ void get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob, float parent_mat[4][4]);
+
void dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
void dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
void dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp
index 908111ebae6..b7eeff3b074 100644
--- a/source/blender/collada/TransformWriter.cpp
+++ b/source/blender/collada/TransformWriter.cpp
@@ -27,11 +27,10 @@
#include "BKE_object.h"
+#include "BLI_math.h"
#include "TransformWriter.h"
-#include "BLI_math.h"
-
void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4])
{
float loc[3], rot[3], scale[3];
@@ -51,7 +50,7 @@ void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4],
converter->mat4_to_dae_double(dmat, local);
delete converter;
- TransformBase::decompose(local, loc, rot, NULL, scale);
+ bc_decompose(local, loc, rot, NULL, scale);
if (node.getType() == COLLADASW::Node::JOINT) {
// XXX Why are joints handled differently ?
@@ -116,7 +115,7 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B
case BC_TRANSFORMATION_TYPE_TRANSROTLOC:
{
float loc[3], rot[3], scale[3];
- TransformBase::decompose(f_obmat, loc, rot, NULL, scale);
+ bc_decompose(f_obmat, loc, rot, NULL, scale);
add_transform(node, loc, rot, scale);
break;
}
diff --git a/source/blender/collada/TransformWriter.h b/source/blender/collada/TransformWriter.h
index 7f69a4b9c95..5bb13d4aac9 100644
--- a/source/blender/collada/TransformWriter.h
+++ b/source/blender/collada/TransformWriter.h
@@ -33,9 +33,10 @@
#include "DNA_object_types.h"
#include "collada_internal.h"
+#include "collada_utils.h"
#include "collada.h"
-class TransformWriter : protected TransformBase
+class TransformWriter
{
protected:
void add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4]);
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index fe8b1d2320a..024bc4a4a5c 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -48,7 +48,8 @@ int collada_import(bContext *C,
int find_chains,
int auto_connect,
int fix_orientation,
- int min_chain_length)
+ int min_chain_length,
+ int keep_bind_info)
{
ImportSettings import_settings;
@@ -58,6 +59,7 @@ int collada_import(bContext *C,
import_settings.find_chains = find_chains != 0;
import_settings.fix_orientation = fix_orientation != 0;
import_settings.min_chain_length = min_chain_length;
+ import_settings.keep_bind_info = keep_bind_info !=0;
DocumentImporter imp(C, &import_settings);
if (imp.import()) return 1;
@@ -78,8 +80,7 @@ int collada_export(Scene *sce,
int deform_bones_only,
int active_uv_only,
- int include_uv_textures,
- int include_material_textures,
+ BC_export_texture_type export_texture_type,
int use_texture_copies,
int triangulate,
@@ -87,7 +88,9 @@ int collada_export(Scene *sce,
int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
- int open_sim)
+ int open_sim,
+ int limit_precision,
+ int keep_bind_info)
{
ExportSettings export_settings;
@@ -102,8 +105,7 @@ int collada_export(Scene *sce,
export_settings.deform_bones_only = deform_bones_only != 0;
export_settings.active_uv_only = active_uv_only != 0;
- export_settings.include_uv_textures = include_uv_textures != 0;
- export_settings.include_material_textures= include_material_textures != 0;
+ export_settings.export_texture_type = export_texture_type;
export_settings.use_texture_copies = use_texture_copies != 0;
export_settings.triangulate = triangulate != 0;
@@ -112,7 +114,8 @@ int collada_export(Scene *sce,
export_settings.sort_by_name = sort_by_name != 0;
export_settings.export_transformation_type = export_transformation_type;
export_settings.open_sim = open_sim != 0;
-
+ export_settings.limit_precision = limit_precision != 0;
+ export_settings.keep_bind_info = keep_bind_info !=0;
int includeFilter = OB_REL_NONE;
if (export_settings.include_armatures) includeFilter |= OB_REL_MOD_ARMATURE;
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index a4416608584..d31f5a8ba62 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -46,6 +46,11 @@ typedef enum BC_export_transformation_type {
BC_TRANSFORMATION_TYPE_TRANSROTLOC
} BC_export_transformation_type;
+typedef enum BC_export_texture_type {
+ BC_TEXTURE_TYPE_MAT,
+ BC_TEXTURE_TYPE_UV
+} BC_export_texture_type;
+
struct bContext;
struct Scene;
@@ -58,7 +63,9 @@ int collada_import(struct bContext *C,
int find_chains,
int auto_connect,
int fix_orientation,
- int min_chain_length);
+ int min_chain_length,
+
+ int keep_bind_info);
int collada_export(struct Scene *sce,
const char *filepath,
@@ -72,8 +79,7 @@ int collada_export(struct Scene *sce,
int deform_bones_only,
int active_uv_only,
- int include_uv_textures,
- int include_material_textures,
+ BC_export_texture_type export_texture_type,
int use_texture_copies,
int triangulate,
@@ -81,9 +87,10 @@ int collada_export(struct Scene *sce,
int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
- int open_sim);
-
+ int open_sim,
+ int limit_precision,
+ int keep_bind_info);
#ifdef __cplusplus
}
diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp
index 38855013ee1..8974acb3460 100644
--- a/source/blender/collada/collada_internal.cpp
+++ b/source/blender/collada/collada_internal.cpp
@@ -33,11 +33,8 @@
UnitConverter::UnitConverter() : unit(), up_axis(COLLADAFW::FileInfo::Z_UP)
{
- unit_m4(x_up_mat4);
- rotate_m4(x_up_mat4, 'Y', -0.5 * M_PI);
-
- unit_m4(y_up_mat4);
- rotate_m4(y_up_mat4, 'X', 0.5 * M_PI);
+ axis_angle_to_mat4_single(x_up_mat4, 'Y', -0.5 * M_PI);
+ axis_angle_to_mat4_single(y_up_mat4, 'X', 0.5 * M_PI);
unit_m4(z_up_mat4);
unit_m4(scale_mat4);
@@ -165,18 +162,6 @@ void UnitConverter::calculate_scale(Scene &sce)
size_to_mat4(scale_mat4, rescale);
}
-void TransformBase::decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
-{
- mat4_to_size(size, mat);
- if (eul) {
- mat4_to_eul(eul, mat);
- }
- if (quat) {
- mat4_to_quat(quat, mat);
- }
- copy_v3_v3(loc, mat[3]);
-}
-
/**
* Translation map.
* Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be
@@ -344,7 +329,12 @@ std::string get_light_id(Object *ob)
std::string get_joint_id(Bone *bone, Object *ob_arm)
{
- return translate_id(/*id_name(ob_arm) + "_" +*/ bone->name);
+ return translate_id(id_name(ob_arm) + "_" + bone->name);
+}
+
+std::string get_joint_sid(Bone *bone, Object *ob_arm)
+{
+ return translate_id(bone->name);
}
std::string get_camera_id(Object *ob)
@@ -354,7 +344,13 @@ std::string get_camera_id(Object *ob)
std::string get_material_id(Material *mat)
{
- return translate_id(id_name(mat)) + "-material";
+ std::string id = id_name(mat);
+ return get_material_id_from_id(id);
+}
+
+std::string get_material_id_from_id(std::string id)
+{
+ return translate_id(id) + "-material";
}
std::string get_morph_id(Object *ob)
diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h
index 4aa637a6876..5f3fa34edc1 100644
--- a/source/blender/collada/collada_internal.h
+++ b/source/blender/collada/collada_internal.h
@@ -85,12 +85,6 @@ public:
};
-class TransformBase
-{
-public:
- void decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size);
-};
-
extern void clear_global_id_map();
/** Look at documentation of translate_map */
extern std::string translate_id(const std::string &id);
@@ -104,10 +98,12 @@ extern std::string get_geometry_id(Object *ob, bool use_instantiation);
extern std::string get_light_id(Object *ob);
extern std::string get_joint_id(Bone *bone, Object *ob_arm);
+extern std::string get_joint_sid(Bone *bone, Object *ob_arm);
extern std::string get_camera_id(Object *ob);
extern std::string get_material_id(Material *mat);
+extern std::string get_material_id_from_id(std::string id);
extern std::string get_morph_id(Object *ob);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index 2efa8b21d81..b09732f9102 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -32,7 +32,7 @@
#include "COLLADAFWMeshPrimitive.h"
#include "COLLADAFWMeshVertexData.h"
-#include "collada_utils.h"
+#include <set>
extern "C" {
#include "DNA_modifier_types.h"
@@ -63,6 +63,9 @@ extern "C" {
#include "bmesh_tools.h"
}
+#include "collada_utils.h"
+#include "ExportSettings.h"
+
float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index)
{
if (index >= array.getValuesCount())
@@ -352,6 +355,28 @@ void bc_match_scale(std::vector<Object *> *objects_done,
}
}
+/*
+ Convenience function to get only the needed components of a matrix
+*/
+void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
+{
+ if (size) {
+ mat4_to_size(size, mat);
+ }
+
+ if (eul) {
+ mat4_to_eul(eul, mat);
+ }
+
+ if (quat) {
+ mat4_to_quat(quat, mat);
+ }
+
+ if (loc) {
+ copy_v3_v3(loc, mat[3]);
+ }
+}
+
void bc_triangulate_mesh(Mesh *me)
{
bool use_beauty = false;
@@ -612,3 +637,356 @@ int BoneExtended::get_use_connect()
{
return this->use_connect;
}
+
+/**
+* Stores a 4*4 matrix as a custom bone property array of size 16
+*/
+void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4])
+{
+ IDProperty *idgroup = (IDProperty *)ebone->prop;
+ if (idgroup == NULL)
+ {
+ IDPropertyTemplate val = { 0 };
+ idgroup = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties");
+ ebone->prop = idgroup;
+ }
+
+ IDPropertyTemplate val = { 0 };
+ val.array.len = 16;
+ val.array.type = IDP_FLOAT;
+
+ IDProperty *data = IDP_New(IDP_ARRAY, &val, key);
+ float *array = (float *)IDP_Array(data);
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ array[4 * i + j] = mat[i][j];
+
+ IDP_AddToGroup(idgroup, data);
+}
+
+#if 0
+/**
+* Stores a Float value as a custom bone property
+*
+* Note: This function is currently not needed. Keep for future usage
+*/
+static void bc_set_IDProperty(EditBone *ebone, const char *key, float value)
+{
+ if (ebone->prop == NULL)
+ {
+ IDPropertyTemplate val = { 0 };
+ ebone->prop = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties");
+ }
+
+ IDProperty *pgroup = (IDProperty *)ebone->prop;
+ IDPropertyTemplate val = { 0 };
+ IDProperty *prop = IDP_New(IDP_FLOAT, &val, key);
+ IDP_Float(prop) = value;
+ IDP_AddToGroup(pgroup, prop);
+
+}
+#endif
+
+/*
+* Get a custom property when it exists.
+* This function is also used to check if a property exists.
+*/
+IDProperty *bc_get_IDProperty(Bone *bone, std::string key)
+{
+ return (bone->prop == NULL) ? NULL : IDP_GetPropertyFromGroup(bone->prop, key.c_str());
+}
+
+/**
+* Read a custom bone property and convert to float
+* Return def if the property does not exist.
+*/
+float bc_get_property(Bone *bone, std::string key, float def)
+{
+ float result = def;
+ IDProperty *property = bc_get_IDProperty(bone, key);
+ if (property) {
+ switch (property->type) {
+ case IDP_INT:
+ result = (float)(IDP_Int(property));
+ break;
+ case IDP_FLOAT:
+ result = (float)(IDP_Float(property));
+ break;
+ case IDP_DOUBLE:
+ result = (float)(IDP_Double(property));
+ break;
+ default:
+ result = def;
+ }
+ }
+ return result;
+}
+
+/**
+* Read a custom bone property and convert to matrix
+* Return true if conversion was succesfull
+*
+* Return false if:
+* - the property does not exist
+* - is not an array of size 16
+*/
+bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
+{
+ IDProperty *property = bc_get_IDProperty(bone, key);
+ if (property && property->type == IDP_ARRAY && property->len == 16) {
+ float *array = (float *)IDP_Array(property);
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ mat[i][j] = array[4 * i + j];
+ return true;
+ }
+ return false;
+}
+
+/**
+* get a vector that is stored in 3 custom properties (used in Blender <= 2.78)
+*/
+void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3])
+{
+ val[0] = bc_get_property(bone, key + "_x", def[0]);
+ val[1] = bc_get_property(bone, key + "_y", def[1]);
+ val[2] = bc_get_property(bone, key + "_z", def[2]);
+}
+
+/**
+* Check if vector exist stored in 3 custom properties (used in Blender <= 2.78)
+*/
+static bool has_custom_props(Bone *bone, bool enabled, std::string key)
+{
+ if (!enabled)
+ return false;
+
+ return (bc_get_IDProperty(bone, key + "_x")
+ || bc_get_IDProperty(bone, key + "_y")
+ || bc_get_IDProperty(bone, key + "_z"));
+
+}
+
+/**
+* Check if custom information about bind matrix exists and modify the from_mat
+* accordingly.
+*
+* Note: This is old style for Blender <= 2.78 only kept for compatibility
+*/
+void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float from_mat[4][4], bool use_local_space)
+{
+ float loc[3];
+ float rot[3];
+ float scale[3];
+ static const float V0[3] = { 0, 0, 0 };
+
+ if (!has_custom_props(bone, export_settings->keep_bind_info, "restpose_loc") &&
+ !has_custom_props(bone, export_settings->keep_bind_info, "restpose_rot") &&
+ !has_custom_props(bone, export_settings->keep_bind_info, "restpose_scale"))
+ {
+ /* No need */
+ copy_m4_m4(to_mat, from_mat);
+ return;
+ }
+
+ bc_decompose(from_mat, loc, rot, NULL, scale);
+ loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6);
+
+ if (export_settings->keep_bind_info) {
+ bc_get_property_vector(bone, "restpose_loc", loc, loc);
+
+ if (use_local_space && bone->parent) {
+ Bone *b = bone;
+ while (b->parent) {
+ b = b->parent;
+ float ploc[3];
+ bc_get_property_vector(b, "restpose_loc", ploc, V0);
+ loc[0] += ploc[0];
+ loc[1] += ploc[1];
+ loc[2] += ploc[2];
+ }
+ }
+ }
+
+ if (export_settings->keep_bind_info) {
+ if (bc_get_IDProperty(bone, "restpose_rot_x"))
+ rot[0] = DEG2RADF(bc_get_property(bone, "restpose_rot_x", 0));
+ if (bc_get_IDProperty(bone, "restpose_rot_y"))
+ rot[1] = DEG2RADF(bc_get_property(bone, "restpose_rot_y", 0));
+ if (bc_get_IDProperty(bone, "restpose_rot_z"))
+ rot[2] = DEG2RADF(bc_get_property(bone, "restpose_rot_z", 0));
+ }
+
+ if (export_settings->keep_bind_info) {
+ bc_get_property_vector(bone, "restpose_scale", scale, scale);
+ }
+
+ loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6);
+
+}
+
+/*
+ Make 4*4 matrices better readable
+*/
+void bc_sanitize_mat(float mat[4][4], int precision)
+{
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ mat[i][j] = double_round(mat[i][j], precision);
+}
+
+/*
+* Returns name of Active UV Layer or empty String if no active UV Layer defined.
+* Assuming the Object is of type MESH
+*/
+std::string bc_get_active_uvlayer_name(Object *ob)
+{
+ Mesh *me = (Mesh *)ob->data;
+ return bc_get_active_uvlayer_name(me);
+}
+
+/*
+ * Returns name of Active UV Layer or empty String if no active UV Layer defined
+ */
+std::string bc_get_active_uvlayer_name(Mesh *me)
+{
+ int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ if (num_layers) {
+ return std::string(bc_CustomData_get_active_layer_name(&me->fdata, CD_MTFACE));
+ }
+ return "";
+}
+
+/*
+ * Returns UV Layer name or empty string if layer index is out of range
+ */
+std::string bc_get_uvlayer_name(Mesh *me, int layer)
+{
+ int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ if (num_layers && layer < num_layers) {
+ return std::string(bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, layer));
+ }
+ return "";
+}
+
+/**********************************************************************
+*
+* Return the list of Mesh objects with assigned UVtextures and Images
+* Note: We need to create artificaial materials for each of them
+*
+***********************************************************************/
+std::set<Object *> bc_getUVTexturedObjects(Scene *sce, bool all_uv_layers)
+{
+ std::set <Object *> UVObjects;
+ Base *base = (Base *)sce->base.first;
+
+ while (base) {
+ Object *ob = base->object;
+ bool has_uvimage = false;
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
+
+ for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) {
+ if (all_uv_layers || active_uv_layer == i)
+ {
+ if (me->pdata.layers[i].type == CD_MTEXPOLY) {
+ MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
+ MPoly *mpoly = me->mpoly;
+ for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) {
+
+ Image *ima = txface->tpage;
+ if (ima != NULL) {
+ has_uvimage = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (has_uvimage) {
+ UVObjects.insert(ob);
+ }
+ }
+ base = base->next;
+ }
+ return UVObjects;
+}
+
+/**********************************************************************
+*
+* Return the list of UV Texture images from all exported Mesh Items
+* Note: We need to create one artificial material for each Image.
+*
+***********************************************************************/
+std::set<Image *> bc_getUVImages(Scene *sce, bool all_uv_layers)
+{
+ std::set <Image *> UVImages;
+ Base *base = (Base *)sce->base.first;
+
+ while (base) {
+ Object *ob = base->object;
+ bool has_uvimage = false;
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
+
+ for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) {
+ if (all_uv_layers || active_uv_layer == i)
+ {
+ if (me->pdata.layers[i].type == CD_MTEXPOLY) {
+ MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
+ MPoly *mpoly = me->mpoly;
+ for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) {
+
+ Image *ima = txface->tpage;
+ if (ima != NULL) {
+ if (UVImages.find(ima) == UVImages.end())
+ UVImages.insert(ima);
+ }
+ }
+ }
+ }
+ }
+ }
+ base = base->next;
+ }
+ return UVImages;
+}
+
+/**********************************************************************
+*
+* Return the list of UV Texture images for the given Object
+* Note: We need to create one artificial material for each Image.
+*
+***********************************************************************/
+std::set<Image *> bc_getUVImages(Object *ob, bool all_uv_layers)
+{
+ std::set <Image *> UVImages;
+
+ bool has_uvimage = false;
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
+
+ for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) {
+ if (all_uv_layers || active_uv_layer == i)
+ {
+ if (me->pdata.layers[i].type == CD_MTEXPOLY) {
+ MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
+ MPoly *mpoly = me->mpoly;
+ for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) {
+
+ Image *ima = txface->tpage;
+ if (ima != NULL) {
+ if (UVImages.find(ima) == UVImages.end())
+ UVImages.insert(ima);
+ }
+ }
+ }
+ }
+ }
+ }
+ return UVImages;
+} \ No newline at end of file
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index 7fdbef3b6cb..5447c39e902 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -34,6 +34,7 @@
#include <vector>
#include <map>
+#include <set>
#include <algorithm>
extern "C" {
@@ -53,8 +54,10 @@ extern "C" {
#include "BKE_object.h"
#include "BKE_DerivedMesh.h"
#include "BKE_scene.h"
+#include "BKE_idprop.h"
}
+#include "ImportSettings.h"
#include "ExportSettings.h"
#include "collada_internal.h"
@@ -78,6 +81,7 @@ extern void bc_set_mark(Object *ob);
extern char *bc_CustomData_get_layer_name(const CustomData *data, int type, int n);
extern char *bc_CustomData_get_active_layer_name(const CustomData *data, int type);
+extern char *bc_CustomData_get_layer_name(const CustomData *data, int layer_index, int type);
extern void bc_bubble_sort_by_Object_name(LinkNode *export_set);
extern bool bc_is_root_bone(Bone *aBone, bool deform_bones_only);
@@ -88,11 +92,32 @@ extern std::string bc_url_encode(std::string data);
extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene);
extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &unit_converter, bool scale_to_scene);
+extern void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size);
+
extern void bc_triangulate_mesh(Mesh *me);
extern bool bc_is_leaf_bone(Bone *bone);
extern EditBone *bc_get_edit_bone(bArmature * armature, char *name);
extern int bc_set_layer(int bitfield, int layer, bool enable);
extern int bc_set_layer(int bitfield, int layer);
+extern void bc_sanitize_mat(float mat[4][4], int precision);
+
+extern IDProperty *bc_get_IDProperty(Bone *bone, std::string key);
+extern void bc_set_IDProperty(EditBone *ebone, const char *key, float value);
+extern void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4]);
+
+extern float bc_get_property(Bone *bone, std::string key, float def);
+extern void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3]);
+extern bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4]);
+
+extern void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float world[4][4], bool use_local_space);
+
+extern std::string bc_get_active_uvlayer_name(Object *ob);
+extern std::string bc_get_active_uvlayer_name(Mesh *me);
+extern std::string bc_get_uvlayer_name(Mesh *me, int layer);
+
+extern std::set<Image *> bc_getUVImages(Scene *sce, bool all_uv_layers);
+extern std::set<Image *> bc_getUVImages(Object *ob, bool all_uv_layers);
+extern std::set<Object *> bc_getUVTexturedObjects(Scene *sce, bool all_uv_layers);
class BCPolygonNormalsIndices
{
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 3180e7e4154..3e1dd83112a 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -551,8 +551,4 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
-if(WITH_CYCLES AND WITH_CYCLES_DEBUG)
- add_definitions(-DWITH_CYCLES_DEBUG)
-endif()
-
blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index a5d7704a708..3b24f9c69a2 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -331,19 +331,6 @@ void COM_deinitialize(void);
*/
// void COM_clearCaches(void); // NOT YET WRITTEN
-/**
- * @brief Return a list of highlighted bnodes pointers.
- * @return
- */
-void COM_startReadHighlights(void);
-
-/**
- * @brief check if a bnode is highlighted
- * @param bnode
- * @return
- */
-int COM_isHighlightedbNode(bNode *bnode);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cpp
index a7b464cde29..68439ff8469 100644
--- a/source/blender/compositor/intern/COM_Debug.cpp
+++ b/source/blender/compositor/intern/COM_Debug.cpp
@@ -28,9 +28,11 @@
#include <vector>
extern "C" {
+#include "BLI_sys_types.h"
#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+
#include "DNA_node_types.h"
#include "BKE_appdir.h"
#include "BKE_node.h"
@@ -174,7 +176,7 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system, const NodeOpera
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "%s\\n(%s)", m_op_names[operation].c_str(), typeid(*operation).name());
- len += snprintf(str + len, maxlen > len ? maxlen - len : 0, " (%d,%d)", operation->getWidth(), operation->getHeight());
+ len += snprintf(str + len, maxlen > len ? maxlen - len : 0, " (%u,%u)", operation->getWidth(), operation->getHeight());
int totoutputs = operation->getNumberOfOutputSockets();
if (totoutputs != 0) {
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp
index 39147f3ab84..68f934008a4 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp
@@ -75,82 +75,6 @@ static bool g_openclInitialized = false;
#endif
#endif
-#define MAX_HIGHLIGHT 8
-static bool g_highlightInitialized = false;
-extern "C" {
-static int g_highlightIndex;
-static void **g_highlightedNodes;
-static void **g_highlightedNodesRead;
-
-/* XXX highlighting disabled for now
- * This requires pointers back to DNA data (bNodeTree/bNode) in operations, which is bad!
- * Instead IF we want to keep this feature it should use a weak reference such as bNodeInstanceKey
- */
-#if 0
-#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
-#define HIGHLIGHT(wp) \
-{ \
- ExecutionGroup *group = wp->getExecutionGroup(); \
- if (group->isComplex()) { \
- NodeOperation *operation = group->getOutputOperation(); \
- if (operation->isWriteBufferOperation()) { \
- WriteBufferOperation *writeOperation = (WriteBufferOperation *)operation; \
- NodeOperation *complexOperation = writeOperation->getInput(); \
- bNode *node = complexOperation->getbNode(); \
- if (node) { \
- if (node->original) { \
- node = node->original; \
- } \
- if (g_highlightInitialized && g_highlightedNodes) { \
- if (g_highlightIndex < MAX_HIGHLIGHT) { \
- g_highlightedNodes[g_highlightIndex++] = node; \
- } \
- } \
- } \
- } \
- } \
-}
-#endif /* COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE */
-#else
-# if COM_CURRENT_THREADING_MODEL != COM_TM_NOTHREAD
-#define HIGHLIGHT(wp) {}
-# endif
-#endif
-
-void COM_startReadHighlights()
-{
- if (!g_highlightInitialized) {
- return;
- }
-
- if (g_highlightedNodesRead) {
- MEM_freeN(g_highlightedNodesRead);
- }
-
- g_highlightedNodesRead = g_highlightedNodes;
- g_highlightedNodes = (void **)MEM_callocN(sizeof(void *) * MAX_HIGHLIGHT, __func__);
- g_highlightIndex = 0;
-}
-
-int COM_isHighlightedbNode(bNode *bnode)
-{
- if (!g_highlightInitialized) {
- return false;
- }
-
- if (!g_highlightedNodesRead) {
- return false;
- }
-
- for (int i = 0; i < MAX_HIGHLIGHT; i++) {
- void *p = g_highlightedNodesRead[i];
- if (!p) return false;
- if (p == bnode) return true;
- }
- return false;
-}
-} // end extern "C"
-
#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
void *WorkScheduler::thread_execute_cpu(void *data)
{
@@ -158,7 +82,6 @@ void *WorkScheduler::thread_execute_cpu(void *data)
WorkPackage *work;
BLI_thread_local_set(g_thread_device, device);
while ((work = (WorkPackage *)BLI_thread_queue_pop(g_cpuqueue))) {
- HIGHLIGHT(work);
device->execute(work);
delete work;
}
@@ -172,7 +95,6 @@ void *WorkScheduler::thread_execute_gpu(void *data)
WorkPackage *work;
while ((work = (WorkPackage *)BLI_thread_queue_pop(g_gpuqueue))) {
- HIGHLIGHT(work);
device->execute(work);
delete work;
}
@@ -289,19 +211,6 @@ static void CL_CALLBACK clContextError(const char *errinfo,
void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads)
{
- /* initialize highlighting */
- if (!g_highlightInitialized) {
- if (g_highlightedNodesRead) MEM_freeN(g_highlightedNodesRead);
- if (g_highlightedNodes) MEM_freeN(g_highlightedNodes);
-
- g_highlightedNodesRead = NULL;
- g_highlightedNodes = NULL;
-
- COM_startReadHighlights();
-
- g_highlightInitialized = true;
- }
-
#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
/* deinitialize if number of threads doesn't match */
if (g_cpudevices.size() != num_cpu_threads) {
@@ -439,20 +348,6 @@ void WorkScheduler::deinitialize()
}
#endif
#endif
-
- /* deinitialize highlighting */
- if (g_highlightInitialized) {
- g_highlightInitialized = false;
- if (g_highlightedNodes) {
- MEM_freeN(g_highlightedNodes);
- g_highlightedNodes = NULL;
- }
-
- if (g_highlightedNodesRead) {
- MEM_freeN(g_highlightedNodesRead);
- g_highlightedNodesRead = NULL;
- }
- }
}
int WorkScheduler::current_thread_id()
diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp
index e3dfd69d8ec..40db5efda27 100644
--- a/source/blender/compositor/intern/COM_compositor.cpp
+++ b/source/blender/compositor/intern/COM_compositor.cpp
@@ -64,9 +64,21 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende
/* Make sure node tree has previews.
* Don't create previews in advance, this is done when adding preview operations.
* Reserved preview size is determined by render output for now.
+ *
+ * We fit the aspect into COM_PREVIEW_SIZE x COM_PREVIEW_SIZE image to avoid
+ * insane preview resolution, which might even overflow preview dimensions.
*/
- float aspect = rd->xsch > 0 ? (float)rd->ysch / (float)rd->xsch : 1.0f;
- BKE_node_preview_init_tree(editingtree, COM_PREVIEW_SIZE, (int)(COM_PREVIEW_SIZE * aspect), false);
+ const float aspect = rd->xsch > 0 ? (float)rd->ysch / (float)rd->xsch : 1.0f;
+ int preview_width, preview_height;
+ if (aspect < 1.0f) {
+ preview_width = COM_PREVIEW_SIZE;
+ preview_height = (int)(COM_PREVIEW_SIZE * aspect);
+ }
+ else {
+ preview_width = (int)(COM_PREVIEW_SIZE / aspect);
+ preview_height = COM_PREVIEW_SIZE;
+ }
+ BKE_node_preview_init_tree(editingtree, preview_width, preview_height, false);
/* initialize workscheduler, will check if already done. TODO deinitialize somewhere */
bool use_opencl = (editingtree->flag & NTREE_COM_OPENCL) != 0;
diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.cpp b/source/blender/compositor/nodes/COM_BrightnessNode.cpp
index 053f286c66e..6729571fac0 100644
--- a/source/blender/compositor/nodes/COM_BrightnessNode.cpp
+++ b/source/blender/compositor/nodes/COM_BrightnessNode.cpp
@@ -31,7 +31,9 @@ BrightnessNode::BrightnessNode(bNode *editorNode) : Node(editorNode)
void BrightnessNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
+ bNode *bnode = this->getbNode();
BrightnessOperation *operation = new BrightnessOperation();
+ operation->setUsePremultiply((bnode->custom1 & 1) != 0);
converter.addOperation(operation);
converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cpp
index 9e8b40d8af4..4754f23a167 100644
--- a/source/blender/compositor/nodes/COM_CompositorNode.cpp
+++ b/source/blender/compositor/nodes/COM_CompositorNode.cpp
@@ -41,6 +41,7 @@ void CompositorNode::convertToOperations(NodeConverter &converter, const Composi
NodeInput *depthSocket = this->getInputSocket(2);
CompositorOperation *compositorOperation = new CompositorOperation();
+ compositorOperation->setScene(context.getScene());
compositorOperation->setSceneName(context.getScene()->id.name);
compositorOperation->setRenderData(context.getRenderData());
compositorOperation->setViewName(context.getViewName());
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
index e159886bb46..851d43fc062 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
@@ -27,7 +27,6 @@
#include "COM_MixOperation.h"
#include "COM_SetColorOperation.h"
#include "COM_SetValueOperation.h"
-#include "COM_ChangeHSVOperation.h"
#include "DNA_node_types.h"
#include "COM_HueSaturationValueCorrectOperation.h"
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
index 29c296a896d..36bc176b1a6 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
@@ -37,11 +37,12 @@ HueSaturationValueNode::HueSaturationValueNode(bNode *editorNode) : Node(editorN
void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
- NodeInput *valueSocket = this->getInputSocket(0);
- NodeInput *colorSocket = this->getInputSocket(1);
+ NodeInput *colorSocket = this->getInputSocket(0);
+ NodeInput *hueSocket = this->getInputSocket(1);
+ NodeInput *saturationSocket = this->getInputSocket(2);
+ NodeInput *valueSocket = this->getInputSocket(3);
+ NodeInput *facSocket = this->getInputSocket(4);
NodeOutput *outputSocket = this->getOutputSocket(0);
- bNode *editorsnode = getbNode();
- NodeHueSat *storage = (NodeHueSat *)editorsnode->storage;
ConvertRGBToHSVOperation *rgbToHSV = new ConvertRGBToHSVOperation();
converter.addOperation(rgbToHSV);
@@ -50,9 +51,9 @@ void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const
converter.addOperation(hsvToRGB);
ChangeHSVOperation *changeHSV = new ChangeHSVOperation();
- changeHSV->setHue(storage->hue);
- changeHSV->setSaturation(storage->sat);
- changeHSV->setValue(storage->val);
+ converter.mapInputSocket(hueSocket, changeHSV->getInputSocket(1));
+ converter.mapInputSocket(saturationSocket, changeHSV->getInputSocket(2));
+ converter.mapInputSocket(valueSocket, changeHSV->getInputSocket(3));
converter.addOperation(changeHSV);
MixBlendOperation *blend = new MixBlendOperation();
@@ -64,6 +65,6 @@ void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const
converter.addLink(changeHSV->getOutputSocket(), hsvToRGB->getInputSocket(0));
converter.addLink(hsvToRGB->getOutputSocket(), blend->getInputSocket(2));
converter.mapInputSocket(colorSocket, blend->getInputSocket(1));
- converter.mapInputSocket(valueSocket, blend->getInputSocket(0));
+ converter.mapInputSocket(facSocket, blend->getInputSocket(0));
converter.mapOutputSocket(outputSocket, blend->getOutputSocket());
}
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp
index facd422c217..81891d853d2 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cpp
@@ -95,17 +95,14 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
NodeOperation *operation = NULL;
socket = this->getOutputSocket(index);
bNodeSocket *bnodeSocket = socket->getbNodeSocket();
- RenderPass *rpass = (RenderPass *)BLI_findstring(&rl->passes, bnodeSocket->identifier, offsetof(RenderPass, internal_name));
+ NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage;
+ RenderPass *rpass = (RenderPass *)BLI_findstring(&rl->passes, storage->pass_name, offsetof(RenderPass, name));
int view = 0;
- /* Passes in the file can differ from passes stored in sockets (#36755).
- * Look up the correct file pass using the socket identifier instead.
- */
-#if 0
- NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage;*/
- int passindex = storage->pass_index;*/
- RenderPass *rpass = (RenderPass *)BLI_findlink(&rl->passes, passindex);
-#endif
+ if (STREQ(storage->pass_name, RE_PASSNAME_COMBINED) && STREQ(bnodeSocket->name, "Alpha")) {
+ /* Alpha output is already handled with the associated combined output. */
+ continue;
+ }
/* returns the image view to use for the current active view */
if (BLI_listbase_count_ex(&image->rr->views, 2) > 1) {
@@ -147,17 +144,25 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
if (index == 0 && operation) {
converter.addPreview(operation->getOutputSocket());
}
- if (rpass->passtype == SCE_PASS_COMBINED) {
- BLI_assert(operation != NULL);
- BLI_assert(index < numberOfOutputs - 1);
- NodeOutput *outputSocket = this->getOutputSocket(index + 1);
- SeparateChannelOperation *separate_operation;
- separate_operation = new SeparateChannelOperation();
- separate_operation->setChannel(3);
- converter.addOperation(separate_operation);
- converter.addLink(operation->getOutputSocket(), separate_operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, separate_operation->getOutputSocket());
- index++;
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
+ for (int alphaIndex = 0; alphaIndex < numberOfOutputs; alphaIndex++) {
+ NodeOutput *alphaSocket = this->getOutputSocket(alphaIndex);
+ bNodeSocket *bnodeAlphaSocket = alphaSocket->getbNodeSocket();
+ if (!STREQ(bnodeAlphaSocket->name, "Alpha")) {
+ continue;
+ }
+ NodeImageLayer *alphaStorage = (NodeImageLayer *)bnodeSocket->storage;
+ if (!STREQ(alphaStorage->pass_name, RE_PASSNAME_COMBINED)) {
+ continue;
+ }
+ SeparateChannelOperation *separate_operation;
+ separate_operation = new SeparateChannelOperation();
+ separate_operation->setChannel(3);
+ converter.addOperation(separate_operation);
+ converter.addLink(operation->getOutputSocket(), separate_operation->getInputSocket(0));
+ converter.mapOutputSocket(alphaSocket, separate_operation->getOutputSocket());
+ break;
+ }
}
}
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
index 842edcf35c9..2286db81860 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
@@ -15,8 +15,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Contributor:
- * Jeroen Bakker
+ * Contributor:
+ * Jeroen Bakker
* Monique Dewanchand
*/
@@ -25,78 +25,164 @@
#include "COM_TranslateOperation.h"
#include "COM_RotateOperation.h"
#include "COM_ScaleOperation.h"
+#include "COM_SetColorOperation.h"
#include "COM_SetValueOperation.h"
-
-#ifdef WITH_CYCLES_DEBUG
-# include "RE_pipeline.h"
-#endif
+#include "COM_SetVectorOperation.h"
RenderLayersNode::RenderLayersNode(bNode *editorNode) : Node(editorNode)
{
/* pass */
}
-void RenderLayersNode::testSocketLink(NodeConverter &converter, const CompositorContext &context,
- int outputSocketNumber, RenderLayersBaseProg *operation) const
+void RenderLayersNode::testSocketLink(NodeConverter &converter,
+ const CompositorContext &context,
+ NodeOutput *output,
+ RenderLayersProg *operation,
+ Scene *scene,
+ int layerId,
+ bool is_preview) const
{
- NodeOutput *outputSocket = this->getOutputSocket(outputSocketNumber);
- Scene *scene = (Scene *)this->getbNode()->id;
- short layerId = this->getbNode()->custom1;
-
operation->setScene(scene);
operation->setLayerId(layerId);
operation->setRenderData(context.getRenderData());
operation->setViewName(context.getViewName());
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket());
+ converter.mapOutputSocket(output, operation->getOutputSocket());
converter.addOperation(operation);
-
- if (outputSocketNumber == 0) /* only for image socket */
+
+ if (is_preview) /* only for image socket */
converter.addPreview(operation->getOutputSocket());
}
-void RenderLayersNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void RenderLayersNode::testRenderLink(NodeConverter &converter,
+ const CompositorContext &context,
+ Render *re) const
+{
+ Scene *scene = (Scene *)this->getbNode()->id;
+ const short layerId = this->getbNode()->custom1;
+ RenderResult *rr = RE_AcquireResultRead(re);
+ if (rr == NULL) {
+ missingRenderLink(converter);
+ return;
+ }
+ SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, layerId);
+ if (srl == NULL) {
+ missingRenderLink(converter);
+ return;
+ }
+ RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
+ if (rl == NULL) {
+ missingRenderLink(converter);
+ return;
+ }
+ const int num_outputs = this->getNumberOfOutputSockets();
+ for (int i = 0; i < num_outputs; i++) {
+ NodeOutput *output = this->getOutputSocket(i);
+ NodeImageLayer *storage = (NodeImageLayer*) output->getbNodeSocket()->storage;
+ RenderPass *rpass = (RenderPass*) BLI_findstring(
+ &rl->passes,
+ storage->pass_name,
+ offsetof(RenderPass, name));
+ if (rpass == NULL) {
+ missingSocketLink(converter, output);
+ continue;
+ }
+ RenderLayersProg *operation;
+ bool is_preview;
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED) &&
+ STREQ(output->getbNodeSocket()->name, "Alpha"))
+ {
+ operation = new RenderLayersAlphaProg(rpass->name,
+ COM_DT_VALUE,
+ rpass->channels);
+ is_preview = false;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
+ operation = new RenderLayersDepthProg(rpass->name,
+ COM_DT_VALUE,
+ rpass->channels);
+ is_preview = false;
+ }
+ else {
+ DataType type;
+ switch (rpass->channels) {
+ case 4: type = COM_DT_COLOR; break;
+ case 3: type = COM_DT_VECTOR; break;
+ case 1: type = COM_DT_VALUE; break;
+ default:
+ BLI_assert(!"Unexpected number of channels for pass");
+ type = COM_DT_VALUE;
+ break;
+ }
+ operation = new RenderLayersProg(rpass->name,
+ type,
+ rpass->channels);
+ is_preview = STREQ(output->getbNodeSocket()->name, "Image");
+ }
+ testSocketLink(converter,
+ context,
+ output,
+ operation,
+ scene,
+ layerId,
+ is_preview);
+ }
+}
+
+void RenderLayersNode::missingSocketLink(NodeConverter &converter,
+ NodeOutput *output) const
{
- testSocketLink(converter, context, 0, new RenderLayersColorProg());
- testSocketLink(converter, context, 1, new RenderLayersAlphaProg());
- testSocketLink(converter, context, 2, new RenderLayersDepthProg());
- testSocketLink(converter, context, 3, new RenderLayersNormalOperation());
- testSocketLink(converter, context, 4, new RenderLayersUVOperation());
- testSocketLink(converter, context, 5, new RenderLayersSpeedOperation());
- testSocketLink(converter, context, 6, new RenderLayersColorOperation());
- testSocketLink(converter, context, 7, new RenderLayersDiffuseOperation());
- testSocketLink(converter, context, 8, new RenderLayersSpecularOperation());
- testSocketLink(converter, context, 9, new RenderLayersShadowOperation());
- testSocketLink(converter, context, 10, new RenderLayersAOOperation());
- testSocketLink(converter, context, 11, new RenderLayersReflectionOperation());
- testSocketLink(converter, context, 12, new RenderLayersRefractionOperation());
- testSocketLink(converter, context, 13, new RenderLayersIndirectOperation());
- testSocketLink(converter, context, 14, new RenderLayersObjectIndexOperation());
- testSocketLink(converter, context, 15, new RenderLayersMaterialIndexOperation());
- testSocketLink(converter, context, 16, new RenderLayersMistOperation());
- testSocketLink(converter, context, 17, new RenderLayersEmitOperation());
- testSocketLink(converter, context, 18, new RenderLayersEnvironmentOperation());
-
- // cycles passes
- testSocketLink(converter, context, 19, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_DIRECT));
- testSocketLink(converter, context, 20, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_INDIRECT));
- testSocketLink(converter, context, 21, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_COLOR));
- testSocketLink(converter, context, 22, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_DIRECT));
- testSocketLink(converter, context, 23, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_INDIRECT));
- testSocketLink(converter, context, 24, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_COLOR));
- testSocketLink(converter, context, 25, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_DIRECT));
- testSocketLink(converter, context, 26, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_INDIRECT));
- testSocketLink(converter, context, 27, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_COLOR));
- testSocketLink(converter, context, 28, new RenderLayersCyclesOperation(SCE_PASS_SUBSURFACE_DIRECT));
- testSocketLink(converter, context, 29, new RenderLayersCyclesOperation(SCE_PASS_SUBSURFACE_INDIRECT));
- testSocketLink(converter, context, 30, new RenderLayersCyclesOperation(SCE_PASS_SUBSURFACE_COLOR));
+ NodeOperation *operation;
+ switch (output->getDataType()) {
+ case COM_DT_COLOR:
+ {
+ const float color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ SetColorOperation *color_operation = new SetColorOperation();
+ color_operation->setChannels(color);
+ operation = color_operation;
+ break;
+ }
+ case COM_DT_VECTOR:
+ {
+ const float vector[3] = {0.0f, 0.0f, 0.0f};
+ SetVectorOperation *vector_operation = new SetVectorOperation();
+ vector_operation->setVector(vector);
+ operation = vector_operation;
+ break;
+ }
+ case COM_DT_VALUE:
+ {
+ SetValueOperation *value_operation = new SetValueOperation();
+ value_operation->setValue(0.0f);
+ operation = value_operation;
+ break;
+ }
+ }
+
+ converter.mapOutputSocket(output, operation->getOutputSocket());
+ converter.addOperation(operation);
+}
+
+void RenderLayersNode::missingRenderLink(NodeConverter &converter) const
+{
+ const int num_outputs = this->getNumberOfOutputSockets();
+ for (int i = 0; i < num_outputs; i++) {
+ NodeOutput *output = this->getOutputSocket(i);
+ missingSocketLink(converter, output);
+ }
+}
+
+void RenderLayersNode::convertToOperations(NodeConverter &converter,
+ const CompositorContext &context) const
+{
+ Scene *scene = (Scene *)this->getbNode()->id;
+ Render *re = (scene) ? RE_GetSceneRender(scene) : NULL;
-#ifdef WITH_CYCLES_DEBUG
- {
- Scene *scene = (Scene *)this->getbNode()->id;
- Render *re = RE_GetRender(scene->id.name);
- int debug_pass_type = ((re != NULL) ? RE_debug_pass_type_get(re) : scene->r.debug_pass_type);
- testSocketLink(converter, context, 31, new RenderLayersCyclesDebugOperation(SCE_PASS_DEBUG, debug_pass_type));
+ if (re != NULL) {
+ testRenderLink(converter, context, re);
+ RE_ReleaseResult(re);
+ }
+ else {
+ missingRenderLink(converter);
}
-#endif
}
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.h b/source/blender/compositor/nodes/COM_RenderLayersNode.h
index 5863cbb390c..5c6c5e17d1f 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.h
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.h
@@ -24,6 +24,8 @@
#include "DNA_node_types.h"
#include "COM_RenderLayersProg.h"
+struct Render;
+
/**
* @brief RenderLayersNode
* @ingroup Node
@@ -31,7 +33,21 @@
class RenderLayersNode : public Node {
public:
RenderLayersNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
+ void convertToOperations(NodeConverter &converter,
+ const CompositorContext &context) const;
private:
- void testSocketLink(NodeConverter &converter, const CompositorContext &context, int outputSocketNumber, RenderLayersBaseProg *operation) const;
+ void testSocketLink(NodeConverter &converter,
+ const CompositorContext &context,
+ NodeOutput *output,
+ RenderLayersProg *operation,
+ Scene *scene,
+ int layerId,
+ bool is_preview) const;
+ void testRenderLink(NodeConverter &converter,
+ const CompositorContext &context,
+ Render *re) const;
+
+ void missingSocketLink(NodeConverter &converter,
+ NodeOutput *output) const;
+ void missingRenderLink(NodeConverter &converter) const;
};
diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cpp b/source/blender/compositor/nodes/COM_ScaleNode.cpp
index 61eea9227dc..ef4128a78b4 100644
--- a/source/blender/compositor/nodes/COM_ScaleNode.cpp
+++ b/source/blender/compositor/nodes/COM_ScaleNode.cpp
@@ -52,6 +52,9 @@ void ScaleNode::convertToOperations(NodeConverter &converter, const CompositorCo
converter.mapInputSocket(inputXSocket, operation->getInputSocket(1));
converter.mapInputSocket(inputYSocket, operation->getInputSocket(2));
converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+
+ operation->setVariableSize(inputXSocket->isLinked() ||
+ inputYSocket->isLinked());
break;
}
case CMP_SCALE_SCENEPERCENT:
@@ -67,6 +70,10 @@ void ScaleNode::convertToOperations(NodeConverter &converter, const CompositorCo
converter.addLink(scaleFactorOperation->getOutputSocket(), operation->getInputSocket(1));
converter.addLink(scaleFactorOperation->getOutputSocket(), operation->getInputSocket(2));
converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+
+ operation->setVariableSize(inputXSocket->isLinked() ||
+ inputYSocket->isLinked());
+
break;
}
case CMP_SCALE_RENDERPERCENT:
@@ -81,9 +88,13 @@ void ScaleNode::convertToOperations(NodeConverter &converter, const CompositorCo
operation->setNewHeight(rd->ysch * rd->size / 100.0f);
operation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE);
converter.addOperation(operation);
-
+
converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+
+ operation->setVariableSize(inputXSocket->isLinked() ||
+ inputYSocket->isLinked());
+
break;
}
case CMP_SCALE_ABSOLUTE:
@@ -91,11 +102,15 @@ void ScaleNode::convertToOperations(NodeConverter &converter, const CompositorCo
/* TODO: what is the use of this one.... perhaps some issues when the ui was updated... */
ScaleAbsoluteOperation *operation = new ScaleAbsoluteOperation();
converter.addOperation(operation);
-
+
converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
converter.mapInputSocket(inputXSocket, operation->getInputSocket(1));
converter.mapInputSocket(inputYSocket, operation->getInputSocket(2));
converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+
+ operation->setVariableSize(inputXSocket->isLinked() ||
+ inputYSocket->isLinked());
+
break;
}
}
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cpp b/source/blender/compositor/operations/COM_BrightnessOperation.cpp
index 33e35c3fe3b..c7ba86b66bc 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.cpp
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.cpp
@@ -29,7 +29,14 @@ BrightnessOperation::BrightnessOperation() : NodeOperation()
this->addInputSocket(COM_DT_VALUE);
this->addOutputSocket(COM_DT_COLOR);
this->m_inputProgram = NULL;
+ this->m_use_premultiply = false;
}
+
+void BrightnessOperation::setUsePremultiply(bool use_premultiply)
+{
+ this->m_use_premultiply = use_premultiply;
+}
+
void BrightnessOperation::initExecution()
{
this->m_inputProgram = this->getInputSocketReader(0);
@@ -64,11 +71,16 @@ void BrightnessOperation::executePixelSampled(float output[4], float x, float y,
delta *= -1;
b = a * (brightness + delta);
}
-
+ if (this->m_use_premultiply) {
+ premul_to_straight_v4(inputValue);
+ }
output[0] = a * inputValue[0] + b;
output[1] = a * inputValue[1] + b;
output[2] = a * inputValue[2] + b;
output[3] = inputValue[3];
+ if (this->m_use_premultiply) {
+ straight_to_premul_v4(output);
+ }
}
void BrightnessOperation::deinitExecution()
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.h b/source/blender/compositor/operations/COM_BrightnessOperation.h
index 22086ae11e8..ff492f2b102 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.h
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.h
@@ -34,6 +34,8 @@ private:
SocketReader *m_inputBrightnessProgram;
SocketReader *m_inputContrastProgram;
+ bool m_use_premultiply;
+
public:
BrightnessOperation();
@@ -52,5 +54,6 @@ public:
*/
void deinitExecution();
+ void setUsePremultiply(bool use_premultiply);
};
#endif
diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp b/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp
index 964f1d64667..7ea974a41dc 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp
@@ -25,6 +25,9 @@
ChangeHSVOperation::ChangeHSVOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR);
+ this->addInputSocket(COM_DT_VALUE);
+ this->addInputSocket(COM_DT_VALUE);
+ this->addInputSocket(COM_DT_VALUE);
this->addOutputSocket(COM_DT_COLOR);
this->m_inputOperation = NULL;
}
@@ -32,24 +35,34 @@ ChangeHSVOperation::ChangeHSVOperation() : NodeOperation()
void ChangeHSVOperation::initExecution()
{
this->m_inputOperation = getInputSocketReader(0);
+ this->m_hueOperation = getInputSocketReader(1);
+ this->m_saturationOperation = getInputSocketReader(2);
+ this->m_valueOperation = getInputSocketReader(3);
}
void ChangeHSVOperation::deinitExecution()
{
this->m_inputOperation = NULL;
+ this->m_hueOperation = NULL;
+ this->m_saturationOperation = NULL;
+ this->m_valueOperation = NULL;
}
void ChangeHSVOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float inputColor1[4];
+ float hue[4], saturation[4], value[4];
this->m_inputOperation->readSampled(inputColor1, x, y, sampler);
+ this->m_hueOperation->readSampled(hue, x, y, sampler);
+ this->m_saturationOperation->readSampled(saturation, x, y, sampler);
+ this->m_valueOperation->readSampled(value, x, y, sampler);
- output[0] = inputColor1[0] + (this->m_hue - 0.5f);
+ output[0] = inputColor1[0] + (hue[0] - 0.5f);
if (output[0] > 1.0f) output[0] -= 1.0f;
else if (output[0] < 0.0f) output[0] += 1.0f;
- output[1] = inputColor1[1] * this->m_saturation;
- output[2] = inputColor1[2] * this->m_value;
+ output[1] = inputColor1[1] * saturation[0];
+ output[2] = inputColor1[2] * value[0];
output[3] = inputColor1[3];
}
diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.h b/source/blender/compositor/operations/COM_ChangeHSVOperation.h
index 76025e86b7a..800c09c05ff 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.h
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.h
@@ -32,10 +32,9 @@
class ChangeHSVOperation : public NodeOperation {
private:
SocketReader *m_inputOperation;
-
- float m_hue;
- float m_saturation;
- float m_value;
+ SocketReader *m_hueOperation;
+ SocketReader *m_saturationOperation;
+ SocketReader *m_valueOperation;
public:
/**
@@ -51,9 +50,5 @@ public:
*/
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
- void setHue(float hue) { this->m_hue = hue; }
- void setSaturation(float saturation) { this->m_saturation = saturation; }
- void setValue(float value) { this->m_value = value; }
-
};
#endif
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp
index 76f74c144f6..15ffff2fc90 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cpp
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp
@@ -51,6 +51,7 @@ CompositorOperation::CompositorOperation() : NodeOperation()
this->m_useAlphaInput = false;
this->m_active = false;
+ this->m_scene = NULL;
this->m_sceneName[0] = '\0';
this->m_viewName = NULL;
}
@@ -78,7 +79,7 @@ void CompositorOperation::deinitExecution()
return;
if (!isBreaked()) {
- Render *re = RE_GetRender(this->m_sceneName);
+ Render *re = RE_GetSceneRender(this->m_scene);
RenderResult *rr = RE_AcquireResultWrite(re);
if (rr) {
@@ -217,7 +218,7 @@ void CompositorOperation::determineResolution(unsigned int resolution[2], unsign
// check actual render resolution with cropping it may differ with cropped border.rendering
// FIX for: [31777] Border Crop gives black (easy)
- Render *re = RE_GetRender(this->m_sceneName);
+ Render *re = RE_GetSceneRender(this->m_scene);
if (re) {
RenderResult *rr = RE_AcquireResultRead(re);
if (rr) {
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.h b/source/blender/compositor/operations/COM_CompositorOperation.h
index e81ba520695..269a065a793 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.h
+++ b/source/blender/compositor/operations/COM_CompositorOperation.h
@@ -26,11 +26,14 @@
#include "BLI_rect.h"
#include "BLI_string.h"
+struct Scene;
+
/**
* @brief Compositor output operation
*/
class CompositorOperation : public NodeOperation {
private:
+ const struct Scene *m_scene;
/**
* @brief Scene name, used for getting the render output, includes 'SC' prefix.
*/
@@ -84,6 +87,7 @@ public:
CompositorOperation();
const bool isActiveCompositorOutput() const { return this->m_active; }
void executeRegion(rcti *rect, unsigned int tileNumber);
+ void setScene(const struct Scene *scene) { m_scene = scene; }
void setSceneName(const char *sceneName) { BLI_strncpy(this->m_sceneName, sceneName, sizeof(this->m_sceneName)); }
void setViewName(const char *viewName) { this->m_viewName = viewName; }
void setRenderData(const RenderData *rd) { this->m_rd = rd; }
diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
index e1ada9a8c39..5f78067220a 100644
--- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
@@ -94,4 +94,10 @@ void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y,
output[2] = output[2] * value[0] + in2[2] * mval;
output[3] = in2[3];
+
+ /* Make sure we don't return negative color. */
+ output[0] = max(output[0], 0.0f);
+ output[1] = max(output[1], 0.0f);
+ output[2] = max(output[2], 0.0f);
+ output[3] = max(output[3], 0.0f);
}
diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
index 68ec2be5ebd..6ac1ff9a1eb 100644
--- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
@@ -107,6 +107,12 @@ void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, voi
output[1] = output[1] * value[0] + in2[1] * mval;
output[2] = output[2] * value[0] + in2[2] * mval;
output[3] = output[3] * value[0] + in2[3] * mval;
+
+ /* Make sure we don't return negative color. */
+ output[0] = max(output[0], 0.0f);
+ output[1] = max(output[1], 0.0f);
+ output[2] = max(output[2], 0.0f);
+ output[3] = max(output[3], 0.0f);
}
bool ConvolutionFilterOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp
index 325ef83a529..aa58c0571cf 100644
--- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp
@@ -65,11 +65,11 @@ void DifferenceMatteOperation::executePixelSampled(float output[4], float x, flo
difference = difference / 3.0f;
/* make 100% transparent */
- if (difference < tolerance) {
+ if (difference <= tolerance) {
output[0] = 0.0f;
}
/*in the falloff region, make partially transparent */
- else if (difference < falloff + tolerance) {
+ else if (difference <= falloff + tolerance) {
difference = difference - tolerance;
alpha = difference / falloff;
/*only change if more transparent than before */
diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp
index 957ac5af748..94f407dad86 100644
--- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp
@@ -44,18 +44,18 @@ void GlareSimpleStarOperation::generateGlare(float *data, MemoryBuffer *inputTil
xp = x + i;
tbuf1->read(c, x, y);
mul_v3_fl(c, f1);
- tbuf1->read(tc, (settings->angle ? xm : x), ym);
+ tbuf1->read(tc, (settings->star_45 ? xm : x), ym);
madd_v3_v3fl(c, tc, f2);
- tbuf1->read(tc, (settings->angle ? xp : x), yp);
+ tbuf1->read(tc, (settings->star_45 ? xp : x), yp);
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
tbuf1->writePixel(x, y, c);
tbuf2->read(c, x, y);
mul_v3_fl(c, f1);
- tbuf2->read(tc, xm, (settings->angle ? yp : y));
+ tbuf2->read(tc, xm, (settings->star_45 ? yp : y));
madd_v3_v3fl(c, tc, f2);
- tbuf2->read(tc, xp, (settings->angle ? ym : y));
+ tbuf2->read(tc, xp, (settings->star_45 ? ym : y));
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
tbuf2->writePixel(x, y, c);
@@ -65,26 +65,26 @@ void GlareSimpleStarOperation::generateGlare(float *data, MemoryBuffer *inputTil
}
}
// // B
- for (y = tbuf1->getHeight() - 1 && (!breaked); y >= 0; y--) {
+ for (y = this->getHeight() - 1; y >= 0 && (!breaked); y--) {
ym = y - i;
yp = y + i;
- for (x = tbuf1->getWidth() - 1; x >= 0; x--) {
+ for (x = this->getWidth() - 1; x >= 0; x--) {
xm = x - i;
xp = x + i;
tbuf1->read(c, x, y);
mul_v3_fl(c, f1);
- tbuf1->read(tc, (settings->angle ? xm : x), ym);
+ tbuf1->read(tc, (settings->star_45 ? xm : x), ym);
madd_v3_v3fl(c, tc, f2);
- tbuf1->read(tc, (settings->angle ? xp : x), yp);
+ tbuf1->read(tc, (settings->star_45 ? xp : x), yp);
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
tbuf1->writePixel(x, y, c);
tbuf2->read(c, x, y);
mul_v3_fl(c, f1);
- tbuf2->read(tc, xm, (settings->angle ? yp : y));
+ tbuf2->read(tc, xm, (settings->star_45 ? yp : y));
madd_v3_v3fl(c, tc, f2);
- tbuf2->read(tc, xp, (settings->angle ? ym : y));
+ tbuf2->read(tc, xp, (settings->star_45 ? ym : y));
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
tbuf2->writePixel(x, y, c);
diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
index da6076337b4..535f2952e5d 100644
--- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
@@ -28,7 +28,7 @@ void GlareStreaksOperation::generateGlare(float *data, MemoryBuffer *inputTile,
int x, y, n;
unsigned int nump = 0;
float c1[4], c2[4], c3[4], c4[4];
- float a, ang = DEG2RADF(360.0f) / (float)settings->angle;
+ float a, ang = DEG2RADF(360.0f) / (float)settings->streaks;
int size = inputTile->getWidth() * inputTile->getHeight();
int size4 = size * 4;
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
index 41f7da7c49f..0c2da8415f8 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
@@ -28,55 +28,58 @@ extern "C" {
MovieClipAttributeOperation::MovieClipAttributeOperation() : NodeOperation()
{
this->addOutputSocket(COM_DT_VALUE);
- this->m_valueSet = false;
this->m_framenumber = 0;
this->m_attribute = MCA_X;
this->m_invert = false;
}
-void MovieClipAttributeOperation::executePixelSampled(float output[4],
- float /*x*/, float /*y*/,
- PixelSampler /*sampler*/)
+void MovieClipAttributeOperation::initExecution()
{
- /* TODO(sergey): This code isn't really thread-safe. */
- if (!this->m_valueSet) {
- float loc[2], scale, angle;
- loc[0] = 0.0f;
- loc[1] = 0.0f;
- scale = 1.0f;
- angle = 0.0f;
- if (this->m_clip) {
- int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_clip, this->m_framenumber);
- BKE_tracking_stabilization_data_get(this->m_clip, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle);
- }
- switch (this->m_attribute) {
- case MCA_SCALE:
- this->m_value = scale;
- break;
- case MCA_ANGLE:
- this->m_value = angle;
- break;
- case MCA_X:
- this->m_value = loc[0];
- break;
- case MCA_Y:
- this->m_value = loc[1];
- break;
+ float loc[2], scale, angle;
+ loc[0] = 0.0f;
+ loc[1] = 0.0f;
+ scale = 1.0f;
+ angle = 0.0f;
+ int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(
+ this->m_clip, this->m_framenumber);
+ BKE_tracking_stabilization_data_get(this->m_clip,
+ clip_framenr,
+ getWidth(), getHeight(),
+ loc, &scale, &angle);
+ switch (this->m_attribute) {
+ case MCA_SCALE:
+ this->m_value = scale;
+ break;
+ case MCA_ANGLE:
+ this->m_value = angle;
+ break;
+ case MCA_X:
+ this->m_value = loc[0];
+ break;
+ case MCA_Y:
+ this->m_value = loc[1];
+ break;
+ }
+ if (this->m_invert) {
+ if (this->m_attribute != MCA_SCALE) {
+ this->m_value = -this->m_value;
}
- if (this->m_invert) {
- if (this->m_attribute != MCA_SCALE) {
- this->m_value = -this->m_value;
- }
- else {
- this->m_value = 1.0f / this->m_value;
- }
+ else {
+ this->m_value = 1.0f / this->m_value;
}
- this->m_valueSet = true;
}
+}
+
+void MovieClipAttributeOperation::executePixelSampled(float output[4],
+ float /*x*/, float /*y*/,
+ PixelSampler /*sampler*/)
+{
output[0] = this->m_value;
}
-void MovieClipAttributeOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void MovieClipAttributeOperation::determineResolution(
+ unsigned int resolution[2],
+ unsigned int preferredResolution[2])
{
resolution[0] = preferredResolution[0];
resolution[1] = preferredResolution[1];
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
index 731b9debaf0..659f54c1ca2 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
@@ -39,16 +39,18 @@ class MovieClipAttributeOperation : public NodeOperation {
private:
MovieClip *m_clip;
float m_value;
- bool m_valueSet;
int m_framenumber;
bool m_invert;
MovieClipAttribute m_attribute;
+
public:
/**
* Default constructor
*/
MovieClipAttributeOperation();
-
+
+ void initExecution();
+
/**
* the inner loop of this program
*/
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
index fb8730c9fa0..d6affa6eee9 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
@@ -29,8 +29,6 @@
#include "BLI_math_color.h"
extern "C" {
-# include "BLI_jitter.h"
-
# include "BKE_node.h"
}
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
index a56aa0cbaa6..070b7562b2d 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
@@ -29,8 +29,6 @@
#include "BLI_math_color.h"
extern "C" {
-# include "BLI_jitter.h"
-
# include "BKE_movieclip.h"
# include "BKE_node.h"
# include "BKE_tracking.h"
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
index 099208ce600..d1c654ddb6c 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
@@ -34,20 +34,21 @@ extern "C" {
/* ******** Render Layers Base Prog ******** */
-RenderLayersBaseProg::RenderLayersBaseProg(int renderpass, int elementsize) : NodeOperation()
+RenderLayersProg::RenderLayersProg(const char *passName, DataType type, int elementsize) : NodeOperation(), m_passName(passName)
{
- this->m_renderpass = renderpass;
this->setScene(NULL);
this->m_inputBuffer = NULL;
this->m_elementsize = elementsize;
this->m_rd = NULL;
+
+ this->addOutputSocket(type);
}
-void RenderLayersBaseProg::initExecution()
+void RenderLayersProg::initExecution()
{
Scene *scene = this->getScene();
- Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL;
+ Render *re = (scene) ? RE_GetSceneRender(scene) : NULL;
RenderResult *rr = NULL;
if (re)
@@ -59,10 +60,7 @@ void RenderLayersBaseProg::initExecution()
RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
if (rl) {
- this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_renderpass, this->m_viewName);
- if (this->m_inputBuffer == NULL && this->m_renderpass == SCE_PASS_COMBINED) {
- this->m_inputBuffer = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, this->m_viewName);
- }
+ this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_passName.c_str(), this->m_viewName);
}
}
}
@@ -72,7 +70,7 @@ void RenderLayersBaseProg::initExecution()
}
}
-void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler)
+void RenderLayersProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler)
{
unsigned int offset;
int width = this->getWidth(), height = this->getHeight();
@@ -111,7 +109,7 @@ void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, Pi
}
}
-void RenderLayersBaseProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void RenderLayersProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
#if 0
const RenderData *rd = this->m_rd;
@@ -173,15 +171,15 @@ void RenderLayersBaseProg::executePixelSampled(float output[4], float x, float y
}
}
-void RenderLayersBaseProg::deinitExecution()
+void RenderLayersProg::deinitExecution()
{
this->m_inputBuffer = NULL;
}
-void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
+void RenderLayersProg::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
Scene *sce = this->getScene();
- Render *re = (sce) ? RE_GetRender(sce->id.name) : NULL;
+ Render *re = (sce) ? RE_GetSceneRender(sce) : NULL;
RenderResult *rr = NULL;
resolution[0] = 0;
@@ -207,13 +205,6 @@ void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsig
}
/* ******** Render Layers AO Operation ******** */
-
-RenderLayersAOOperation::RenderLayersAOOperation() : RenderLayersBaseProg(SCE_PASS_AO, 3)
-{
- this->addOutputSocket(COM_DT_COLOR);
-}
-
-
void RenderLayersAOOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float *inputBuffer = this->getInputBuffer();
@@ -227,12 +218,6 @@ void RenderLayersAOOperation::executePixelSampled(float output[4], float x, floa
}
/* ******** Render Layers Alpha Operation ******** */
-
-RenderLayersAlphaProg::RenderLayersAlphaProg() : RenderLayersBaseProg(SCE_PASS_COMBINED, 4)
-{
- this->addOutputSocket(COM_DT_VALUE);
-}
-
void RenderLayersAlphaProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float *inputBuffer = this->getInputBuffer();
@@ -247,27 +232,7 @@ void RenderLayersAlphaProg::executePixelSampled(float output[4], float x, float
}
}
-/* ******** Render Layers Color Operation ******** */
-
-RenderLayersColorOperation::RenderLayersColorOperation() : RenderLayersBaseProg(SCE_PASS_RGBA, 4)
-{
- this->addOutputSocket(COM_DT_COLOR);
-}
-
-/* ******** Render Layers Cycles Operation ******** */
-
-RenderLayersCyclesOperation::RenderLayersCyclesOperation(int pass) : RenderLayersBaseProg(pass, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
/* ******** Render Layers Depth Operation ******** */
-
-RenderLayersDepthProg::RenderLayersDepthProg() : RenderLayersBaseProg(SCE_PASS_Z, 1)
-{
- this->addOutputSocket(COM_DT_VALUE);
-}
-
void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
int ix = x;
@@ -282,134 +247,3 @@ void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float
output[0] = inputBuffer[offset];
}
}
-
-/* ******** Render Layers Diffuse Operation ******** */
-
-RenderLayersDiffuseOperation::RenderLayersDiffuseOperation() : RenderLayersBaseProg(SCE_PASS_DIFFUSE, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Emit Operation ******** */
-
-RenderLayersEmitOperation::RenderLayersEmitOperation() : RenderLayersBaseProg(SCE_PASS_EMIT, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Environment Operation ******** */
-
-RenderLayersEnvironmentOperation::RenderLayersEnvironmentOperation() : RenderLayersBaseProg(SCE_PASS_ENVIRONMENT, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Image Operation ******** */
-
-RenderLayersColorProg::RenderLayersColorProg() : RenderLayersBaseProg(SCE_PASS_COMBINED, 4)
-{
- this->addOutputSocket(COM_DT_COLOR);
-}
-
-/* ******** Render Layers Indirect Operation ******** */
-
-RenderLayersIndirectOperation::RenderLayersIndirectOperation() : RenderLayersBaseProg(SCE_PASS_INDIRECT, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Material Index Operation ******** */
-
-RenderLayersMaterialIndexOperation::RenderLayersMaterialIndexOperation() : RenderLayersBaseProg(SCE_PASS_INDEXMA, 1)
-{
- this->addOutputSocket(COM_DT_VALUE);
-}
-
-/* ******** Render Layers Mist Operation ******** */
-
-RenderLayersMistOperation::RenderLayersMistOperation() : RenderLayersBaseProg(SCE_PASS_MIST, 1)
-{
- this->addOutputSocket(COM_DT_VALUE);
-}
-
-/* ******** Render Layers Normal Operation ******** */
-
-RenderLayersNormalOperation::RenderLayersNormalOperation() : RenderLayersBaseProg(SCE_PASS_NORMAL, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Object Index Operation ******** */
-
-RenderLayersObjectIndexOperation::RenderLayersObjectIndexOperation() : RenderLayersBaseProg(SCE_PASS_INDEXOB, 1)
-{
- this->addOutputSocket(COM_DT_VALUE);
-}
-
-/* ******** Render Layers Reflection Operation ******** */
-
-RenderLayersReflectionOperation::RenderLayersReflectionOperation() : RenderLayersBaseProg(SCE_PASS_REFLECT, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Refraction Operation ******** */
-
-RenderLayersRefractionOperation::RenderLayersRefractionOperation() : RenderLayersBaseProg(SCE_PASS_REFRACT, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Shadow Operation ******** */
-
-RenderLayersShadowOperation::RenderLayersShadowOperation() : RenderLayersBaseProg(SCE_PASS_SHADOW, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Specular Operation ******** */
-
-RenderLayersSpecularOperation::RenderLayersSpecularOperation() : RenderLayersBaseProg(SCE_PASS_SPEC, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Speed Operation ******** */
-
-RenderLayersSpeedOperation::RenderLayersSpeedOperation() : RenderLayersBaseProg(SCE_PASS_VECTOR, 4)
-{
- this->addOutputSocket(COM_DT_COLOR);
-}
-
-/* ******** Render Layers UV Operation ******** */
-
-RenderLayersUVOperation::RenderLayersUVOperation() : RenderLayersBaseProg(SCE_PASS_UV, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Debug Render Layers Cycles Operation ******** */
-
-#ifdef WITH_CYCLES_DEBUG
-
-RenderLayersCyclesDebugOperation::RenderLayersCyclesDebugOperation(
- int pass,
- int debug_pass_type)
- : RenderLayersBaseProg(pass, RE_debug_pass_num_channels_get(debug_pass_type))
-{
- switch (m_elementsize) {
- case 1:
- this->addOutputSocket(COM_DT_VALUE);
- break;
- case 3:
- this->addOutputSocket(COM_DT_VECTOR);
- break;
- case 4:
- this->addOutputSocket(COM_DT_COLOR);
- break;
- default:
- BLI_assert(!"Unkown debug pass type element size.");
- }
-}
-
-#endif
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h
index 89eb2a6954d..1be15906770 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.h
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.h
@@ -40,7 +40,7 @@ extern "C" {
*
* @todo: rename to operation.
*/
-class RenderLayersBaseProg : public NodeOperation {
+class RenderLayersProg : public NodeOperation {
protected:
/**
* Reference to the scene object.
@@ -65,7 +65,7 @@ protected:
/**
* renderpass where this operation needs to get its data from
*/
- int m_renderpass;
+ std::string m_passName;
int m_elementsize;
@@ -73,11 +73,6 @@ protected:
* @brief render data used for active rendering
*/
const RenderData *m_rd;
-
- /**
- * Constructor
- */
- RenderLayersBaseProg(int renderpass, int elementsize);
/**
* Determine the output resolution. The resolution is retrieved from the Renderer
@@ -92,6 +87,10 @@ protected:
void doInterpolation(float output[4], float x, float y, PixelSampler sampler);
public:
/**
+ * Constructor
+ */
+ RenderLayersProg(const char *passName, DataType type, int elementsize);
+ /**
* setter for the scene field. Will be called from
* @see RenderLayerNode to set the actual scene where
* the data will be retrieved from.
@@ -108,116 +107,25 @@ public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
-class RenderLayersAOOperation : public RenderLayersBaseProg {
+class RenderLayersAOOperation : public RenderLayersProg {
public:
- RenderLayersAOOperation();
+ RenderLayersAOOperation(const char *passName, DataType type, int elementsize)
+ : RenderLayersProg(passName, type, elementsize) {}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
-class RenderLayersAlphaProg : public RenderLayersBaseProg {
+class RenderLayersAlphaProg : public RenderLayersProg {
public:
- RenderLayersAlphaProg();
+ RenderLayersAlphaProg(const char *passName, DataType type, int elementsize)
+ : RenderLayersProg(passName, type, elementsize) {}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
-class RenderLayersColorOperation : public RenderLayersBaseProg {
-public:
- RenderLayersColorOperation();
-};
-
-class RenderLayersCyclesOperation : public RenderLayersBaseProg {
-public:
- RenderLayersCyclesOperation(int pass);
-};
-
-class RenderLayersDepthProg : public RenderLayersBaseProg {
+class RenderLayersDepthProg : public RenderLayersProg {
public:
- RenderLayersDepthProg();
+ RenderLayersDepthProg(const char *passName, DataType type, int elementsize)
+ : RenderLayersProg(passName, type, elementsize) {}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
-class RenderLayersDiffuseOperation : public RenderLayersBaseProg {
-public:
- RenderLayersDiffuseOperation();
-};
-
-class RenderLayersEmitOperation : public RenderLayersBaseProg {
-public:
- RenderLayersEmitOperation();
-};
-
-class RenderLayersEnvironmentOperation : public RenderLayersBaseProg {
-public:
- RenderLayersEnvironmentOperation();
-};
-
-/// @todo rename to image operation
-class RenderLayersColorProg : public RenderLayersBaseProg {
-public:
- RenderLayersColorProg();
-};
-
-class RenderLayersIndirectOperation : public RenderLayersBaseProg {
-public:
- RenderLayersIndirectOperation();
-};
-
-class RenderLayersMaterialIndexOperation : public RenderLayersBaseProg {
-public:
- RenderLayersMaterialIndexOperation();
-};
-
-class RenderLayersMistOperation : public RenderLayersBaseProg {
-public:
- RenderLayersMistOperation();
-};
-
-class RenderLayersNormalOperation : public RenderLayersBaseProg {
-public:
- RenderLayersNormalOperation();
-};
-
-class RenderLayersObjectIndexOperation : public RenderLayersBaseProg {
-public:
- RenderLayersObjectIndexOperation();
-};
-
-class RenderLayersReflectionOperation : public RenderLayersBaseProg {
-public:
- RenderLayersReflectionOperation();
-};
-
-class RenderLayersRefractionOperation : public RenderLayersBaseProg {
-public:
- RenderLayersRefractionOperation();
-};
-
-class RenderLayersShadowOperation : public RenderLayersBaseProg {
-public:
- RenderLayersShadowOperation();
-};
-
-class RenderLayersSpecularOperation : public RenderLayersBaseProg {
-public:
- RenderLayersSpecularOperation();
-};
-
-class RenderLayersSpeedOperation : public RenderLayersBaseProg {
-public:
- RenderLayersSpeedOperation();
-};
-
-class RenderLayersUVOperation : public RenderLayersBaseProg {
-public:
- RenderLayersUVOperation();
-};
-
-#ifdef WITH_CYCLES_DEBUG
-class RenderLayersCyclesDebugOperation : public RenderLayersBaseProg {
-public:
- RenderLayersCyclesDebugOperation(int pass,
- int debug_pass_type);
-};
-#endif
-
#endif
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cpp b/source/blender/compositor/operations/COM_ScaleOperation.cpp
index 117ae743ee7..b498b359144 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScaleOperation.cpp
@@ -36,6 +36,7 @@ BaseScaleOperation::BaseScaleOperation()
#else
m_sampler = -1;
#endif
+ m_variable_size = false;
}
ScaleOperation::ScaleOperation() : BaseScaleOperation()
@@ -87,20 +88,27 @@ void ScaleOperation::executePixelSampled(float output[4], float x, float y, Pixe
bool ScaleOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
- float scaleX[4];
- float scaleY[4];
-
- this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST);
- this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST);
+ if (!m_variable_size) {
+ float scaleX[4];
+ float scaleY[4];
- const float scx = scaleX[0];
- const float scy = scaleY[0];
+ this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST);
+ this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST);
- newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / scx;
- newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / scx;
- newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / scy;
- newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / scy;
+ const float scx = scaleX[0];
+ const float scy = scaleY[0];
+ newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / scx;
+ newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / scx;
+ newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / scy;
+ newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / scy;
+ }
+ else {
+ newInput.xmax = this->getWidth();
+ newInput.xmin = 0;
+ newInput.ymax = this->getHeight();
+ newInput.ymin = 0;
+ }
return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
@@ -162,24 +170,32 @@ void ScaleAbsoluteOperation::executePixelSampled(float output[4], float x, float
bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
- float scaleX[4];
- float scaleY[4];
-
- this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST);
- this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST);
-
- const float scx = scaleX[0];
- const float scy = scaleY[0];
- const float width = this->getWidth();
- const float height = this->getHeight();
- //div
- float relateveXScale = scx / width;
- float relateveYScale = scy / height;
-
- newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / relateveXScale;
- newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / relateveXScale;
- newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / relateveYScale;
- newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / relateveYScale;
+ if (!m_variable_size) {
+ float scaleX[4];
+ float scaleY[4];
+
+ this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST);
+ this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST);
+
+ const float scx = scaleX[0];
+ const float scy = scaleY[0];
+ const float width = this->getWidth();
+ const float height = this->getHeight();
+ //div
+ float relateveXScale = scx / width;
+ float relateveYScale = scy / height;
+
+ newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / relateveXScale;
+ newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / relateveXScale;
+ newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / relateveYScale;
+ newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / relateveYScale;
+ }
+ else {
+ newInput.xmax = this->getWidth();
+ newInput.xmin = 0;
+ newInput.ymax = this->getHeight();
+ newInput.ymin = 0;
+ }
return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
@@ -271,9 +287,9 @@ bool ScaleFixedSizeOperation::determineDependingAreaOfInterest(rcti *input, Read
{
rcti newInput;
- newInput.xmax = (input->xmax - m_offsetX) * this->m_relX;
+ newInput.xmax = (input->xmax - m_offsetX) * this->m_relX + 1;
newInput.xmin = (input->xmin - m_offsetX) * this->m_relX;
- newInput.ymax = (input->ymax - m_offsetY) * this->m_relY;
+ newInput.ymax = (input->ymax - m_offsetY) * this->m_relY + 1;
newInput.ymin = (input->ymin - m_offsetY) * this->m_relY;
return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h
index 706a5898027..17cd31f9710 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.h
+++ b/source/blender/compositor/operations/COM_ScaleOperation.h
@@ -28,6 +28,7 @@
class BaseScaleOperation : public NodeOperation {
public:
void setSampler(PixelSampler sampler) { this->m_sampler = (int) sampler; }
+ void setVariableSize(bool variable_size) { m_variable_size = variable_size; };
protected:
BaseScaleOperation();
@@ -35,6 +36,7 @@ protected:
PixelSampler getEffectiveSampler(PixelSampler sampler) { return (m_sampler == -1) ? sampler : (PixelSampler) m_sampler; }
int m_sampler;
+ bool m_variable_size;
};
class ScaleOperation : public BaseScaleOperation {
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp
index 6bfd8ae3888..d0c72935b16 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cpp
+++ b/source/blender/compositor/operations/COM_TextureOperation.cpp
@@ -41,6 +41,7 @@ TextureBaseOperation::TextureBaseOperation() : NodeOperation()
this->m_rd = NULL;
this->m_pool = NULL;
this->m_sceneColorManage = false;
+ setComplex(true);
}
TextureOperation::TextureOperation() : TextureBaseOperation()
{
@@ -155,31 +156,3 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y
output[0] = output[1] = output[2] = output[3];
}
}
-
-MemoryBuffer *TextureBaseOperation::createMemoryBuffer(rcti * /*rect2*/)
-{
- int height = getHeight();
- int width = getWidth();
- DataType datatype = this->getOutputSocket()->getDataType();
- int add = 4;
- if (datatype == COM_DT_VALUE) {
- add = 1;
- }
-
- rcti rect;
- rect.xmin = 0;
- rect.ymin = 0;
- rect.xmax = width;
- rect.ymax = height;
- MemoryBuffer *result = new MemoryBuffer(datatype, &rect);
-
- float *data = result->getBuffer();
-
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++, data += add) {
- this->executePixelSampled(data, x, y, COM_PS_NEAREST);
- }
- }
-
- return result;
-}
diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h
index 4cc203b54a2..59ff58a7289 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.h
+++ b/source/blender/compositor/operations/COM_TextureOperation.h
@@ -59,8 +59,6 @@ protected:
* Constructor
*/
TextureBaseOperation();
-
- MemoryBuffer *createMemoryBuffer(rcti *rect2);
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
index 1ec52571be8..9ff0bf9ce12 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
@@ -286,9 +286,9 @@ void InverseSearchRadiusOperation::initExecution()
this->m_inputRadius = this->getInputSocketReader(0);
}
-voi *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
+void *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
{
- MemoryBuffer * data = new MemoryBuffer(NULL, rect);
+ MemoryBuffer * data = new MemoryBuffer(COM_DT_COLOR, rect);
float *buffer = data->getBuffer();
int x, y;
int width = this->m_inputRadius->getWidth();
@@ -343,7 +343,7 @@ voi *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
void InverseSearchRadiusOperation::executePixelChunk(float output[4], int x, int y, void *data)
{
MemoryBuffer *buffer = (MemoryBuffer *)data;
- buffer->readNoCheck(color, x, y);
+ buffer->readNoCheck(output, x, y);
}
void InverseSearchRadiusOperation::deinitializeTileData(rcti *rect, void *data)
diff --git a/source/blender/datatoc/CMakeLists.txt b/source/blender/datatoc/CMakeLists.txt
index 0f123fbf9f0..af7f954cad1 100644
--- a/source/blender/datatoc/CMakeLists.txt
+++ b/source/blender/datatoc/CMakeLists.txt
@@ -62,4 +62,9 @@ if(NOT WITH_HEADLESS)
add_executable(datatoc_icon ${SRC})
target_link_libraries(datatoc_icon ${PNG_LIBRARIES} ${ZLIB_LIBRARIES})
+ # PNG library uses pow() and floow(), so seems -lm is required for proper
+ # workign binary.
+ if(UNIX AND NOT APPLE)
+ target_link_libraries(datatoc_icon m)
+ endif()
endif()
diff --git a/source/blender/datatoc/datatoc.c b/source/blender/datatoc/datatoc.c
index 4e49a9a7694..ffccca98f99 100644
--- a/source/blender/datatoc/datatoc.c
+++ b/source/blender/datatoc/datatoc.c
@@ -91,6 +91,11 @@ int main(int argc, char **argv)
}
fprintf(fpout, "/* DataToC output of file <%s> */\n\n", argv[1]);
+
+ /* Quiet 'missing-variable-declarations' warning. */
+ fprintf(fpout, "extern int datatoc_%s_size;\n", argv[1]);
+ fprintf(fpout, "extern char datatoc_%s[];\n\n", argv[1]);
+
fprintf(fpout, "int datatoc_%s_size = %d;\n", argv[1], (int)size);
fprintf(fpout, "char datatoc_%s[] = {\n", argv[1]);
while (size--) {
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index e635256cda6..33a7628c68d 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -87,8 +87,8 @@ set(SRC
intern/depsgraph_intern.h
intern/depsgraph_types.h
+ util/deg_util_foreach.h
util/deg_util_function.h
- util/deg_util_hash.h
)
if(WITH_CXX11)
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index 945a4785b9c..59b10b95d49 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -134,6 +134,9 @@ void DEG_ids_clear_recalc(struct Main *bmain);
/* Flush updates for all IDs */
void DEG_ids_flush_tagged(struct Main *bmain);
+/* Flush updates for IDs in a single scene. */
+void DEG_scene_flush_update(struct Main *bmain, struct Scene *scene);
+
/* Check if something was changed in the database and inform
* editors about this.
*/
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index fdc86540171..b65d921cfd1 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -153,7 +153,8 @@ void DEG_add_object_cache_relation(struct DepsNodeHandle *handle,
eDepsObjectComponentType component,
const char *description);
-/* TODO(sergey): Remove once all geometry update is granular. */
+
+struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *handle);
void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag);
/* Utility functions for physics modifiers */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index aedd00685b3..e3494e4756e 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -30,15 +30,13 @@
#include "intern/builder/deg_builder.h"
-// TODO(sergey): Use own wrapper over STD.
-#include <stack>
-
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
#include "DNA_ID.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLI_stack.h"
#include "intern/depsgraph.h"
#include "intern/depsgraph_types.h"
@@ -52,14 +50,6 @@
namespace DEG {
-string deg_fcurve_id_name(const FCurve *fcu)
-{
- char index_buf[32];
- // TODO(sergey): Use int-to-string utility or so.
- BLI_snprintf(index_buf, sizeof(index_buf), "[%d]", fcu->array_index);
- return string(fcu->rna_path) + index_buf;
-}
-
static bool check_object_needs_evaluation(Object *object)
{
if (object->recalc & OB_RECALC_ALL) {
@@ -77,72 +67,79 @@ static bool check_object_needs_evaluation(Object *object)
return false;
}
-void deg_graph_build_finalize(Depsgraph *graph)
+void deg_graph_build_flush_layers(Depsgraph *graph)
{
- /* STEP 1: Make sure new invisible dependencies are ready for use.
- *
- * TODO(sergey): This might do a bit of extra tagging, but it's kinda nice
- * to do it ahead of a time and don't spend time on flushing updates on
- * every frame change.
- */
- GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
- {
- if (id_node->layers == 0) {
- ID *id = id_node->id;
- if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- if (check_object_needs_evaluation(object)) {
- id_node->tag_update(graph);
- }
- }
- }
- }
- GHASH_FOREACH_END();
- /* STEP 2: Flush visibility layers from children to parent. */
- std::stack<OperationDepsNode *> stack;
+ BLI_Stack *stack = BLI_stack_new(sizeof(OperationDepsNode *),
+ "DEG flush layers stack");
foreach (OperationDepsNode *node, graph->operations) {
IDDepsNode *id_node = node->owner->owner;
node->done = 0;
node->num_links_pending = 0;
foreach (DepsRelation *rel, node->outlinks) {
- if ((rel->from->type == DEPSNODE_TYPE_OPERATION) &&
+ if ((rel->from->type == DEG_NODE_TYPE_OPERATION) &&
(rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
{
++node->num_links_pending;
}
}
if (node->num_links_pending == 0) {
- stack.push(node);
+ BLI_stack_push(stack, &node);
node->done = 1;
}
node->owner->layers = id_node->layers;
id_node->id->tag |= LIB_TAG_DOIT;
}
- while (!stack.empty()) {
- OperationDepsNode *node = stack.top();
- stack.pop();
+ while (!BLI_stack_is_empty(stack)) {
+ OperationDepsNode *node;
+ BLI_stack_pop(stack, &node);
/* Flush layers to parents. */
foreach (DepsRelation *rel, node->inlinks) {
- if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ if (rel->from->type == DEG_NODE_TYPE_OPERATION) {
OperationDepsNode *from = (OperationDepsNode *)rel->from;
from->owner->layers |= node->owner->layers;
}
}
/* Schedule parent nodes. */
foreach (DepsRelation *rel, node->inlinks) {
- if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ if (rel->from->type == DEG_NODE_TYPE_OPERATION) {
OperationDepsNode *from = (OperationDepsNode *)rel->from;
if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
BLI_assert(from->num_links_pending > 0);
--from->num_links_pending;
}
if (from->num_links_pending == 0 && from->done == 0) {
- stack.push(from);
+ BLI_stack_push(stack, &from);
from->done = 1;
}
}
}
}
+ BLI_stack_free(stack);
+}
+
+void deg_graph_build_finalize(Depsgraph *graph)
+{
+ /* STEP 1: Make sure new invisible dependencies are ready for use.
+ *
+ * TODO(sergey): This might do a bit of extra tagging, but it's kinda nice
+ * to do it ahead of a time and don't spend time on flushing updates on
+ * every frame change.
+ */
+ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
+ {
+ if (id_node->layers == 0) {
+ ID *id = id_node->id;
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if (check_object_needs_evaluation(object)) {
+ id_node->tag_update(graph);
+ }
+ }
+ }
+ }
+ GHASH_FOREACH_END();
+ /* STEP 2: Flush visibility layers from children to parent. */
+ deg_graph_build_flush_layers(graph);
/* STEP 3: Re-tag IDs for update if it was tagged before the relations
* update tag.
*/
@@ -154,19 +151,21 @@ void deg_graph_build_finalize(Depsgraph *graph)
}
GHASH_FOREACH_END();
- ID *id = id_node->id;
- if ((id->tag & LIB_TAG_ID_RECALC_ALL) &&
- (id->tag & LIB_TAG_DOIT))
- {
- id_node->tag_update(graph);
- id->tag &= ~LIB_TAG_DOIT;
- }
- else if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- if (object->recalc & OB_RECALC_ALL) {
+ if ((id_node->layers & graph->layers) != 0 || graph->layers == 0) {
+ ID *id = id_node->id;
+ if ((id->tag & LIB_TAG_ID_RECALC_ALL) &&
+ (id->tag & LIB_TAG_DOIT))
+ {
id_node->tag_update(graph);
id->tag &= ~LIB_TAG_DOIT;
}
+ else if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if (object->recalc & OB_RECALC_ALL) {
+ id_node->tag_update(graph);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ }
}
id_node->finalize_build();
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
index bdc030e3810..b8ea8c8e599 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -38,9 +38,7 @@ namespace DEG {
struct Depsgraph;
-/* Get unique identifier for FCurves and Drivers */
-string deg_fcurve_id_name(const FCurve *fcu);
-
void deg_graph_build_finalize(struct Depsgraph *graph);
+void deg_graph_build_flush_layers(struct Depsgraph *graph);
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index 9b37aaa12ff..3eed0697b5e 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -32,11 +32,9 @@
// TOO(sergey): Use some wrappers over those?
#include <cstdio>
#include <cstdlib>
-#include <stack>
-extern "C" {
#include "BLI_utildefines.h"
-}
+#include "BLI_stack.h"
#include "util/deg_util_foreach.h"
@@ -48,12 +46,6 @@ extern "C" {
namespace DEG {
-struct StackEntry {
- OperationDepsNode *node;
- StackEntry *from;
- DepsRelation *via_relation;
-};
-
void deg_graph_detect_cycles(Depsgraph *graph)
{
enum {
@@ -65,11 +57,19 @@ void deg_graph_detect_cycles(Depsgraph *graph)
NODE_IN_STACK = 2,
};
- std::stack<StackEntry> traversal_stack;
+ struct StackEntry {
+ OperationDepsNode *node;
+ StackEntry *from;
+ DepsRelation *via_relation;
+ };
+
+ BLI_Stack *traversal_stack = BLI_stack_new(sizeof(StackEntry),
+ "DEG detect cycles stack");
+
foreach (OperationDepsNode *node, graph->operations) {
bool has_inlinks = false;
foreach (DepsRelation *rel, node->inlinks) {
- if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ if (rel->from->type == DEG_NODE_TYPE_OPERATION) {
has_inlinks = true;
}
}
@@ -78,7 +78,7 @@ void deg_graph_detect_cycles(Depsgraph *graph)
entry.node = node;
entry.from = NULL;
entry.via_relation = NULL;
- traversal_stack.push(entry);
+ BLI_stack_push(traversal_stack, &entry);
node->tag = NODE_IN_STACK;
}
else {
@@ -87,13 +87,13 @@ void deg_graph_detect_cycles(Depsgraph *graph)
node->done = 0;
}
- while (!traversal_stack.empty()) {
- StackEntry& entry = traversal_stack.top();
- OperationDepsNode *node = entry.node;
+ while (!BLI_stack_is_empty(traversal_stack)) {
+ StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack);
+ OperationDepsNode *node = entry->node;
bool all_child_traversed = true;
for (int i = node->done; i < node->outlinks.size(); ++i) {
DepsRelation *rel = node->outlinks[i];
- if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ if (rel->to->type == DEG_NODE_TYPE_OPERATION) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
if (to->tag == NODE_IN_STACK) {
printf("Dependency cycle detected:\n");
@@ -102,7 +102,7 @@ void deg_graph_detect_cycles(Depsgraph *graph)
node->full_identifier().c_str(),
rel->name);
- StackEntry *current = &entry;
+ StackEntry *current = entry;
while (current->node != to) {
BLI_assert(current != NULL);
printf(" '%s' depends on '%s' through '%s'\n",
@@ -117,9 +117,9 @@ void deg_graph_detect_cycles(Depsgraph *graph)
else if (to->tag == NODE_NOT_VISITED) {
StackEntry new_entry;
new_entry.node = to;
- new_entry.from = &entry;
+ new_entry.from = entry;
new_entry.via_relation = rel;
- traversal_stack.push(new_entry);
+ BLI_stack_push(traversal_stack, &new_entry);
to->tag = NODE_IN_STACK;
all_child_traversed = false;
node->done = i;
@@ -129,9 +129,11 @@ void deg_graph_detect_cycles(Depsgraph *graph)
}
if (all_child_traversed) {
node->tag = NODE_VISITED;
- traversal_stack.pop();
+ BLI_stack_discard(traversal_stack);
}
}
+
+ BLI_stack_free(traversal_stack);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index e312c4e0dcb..17f0c030bd0 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -37,11 +37,11 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BLI_blenlib.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
+extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -81,6 +81,7 @@ extern "C" {
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_mask.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mball.h"
@@ -94,13 +95,13 @@ extern "C" {
#include "BKE_tracking.h"
#include "BKE_world.h"
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-
#include "RNA_access.h"
#include "RNA_types.h"
} /* extern "C" */
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "intern/builder/deg_builder.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
@@ -121,7 +122,7 @@ struct BuilderWalkUserData {
static void modifier_walk(void *user_data,
struct Object * /*ob*/,
struct Object **obpoin,
- int /*cd_flag*/)
+ int /*cb_flag*/)
{
BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
if (*obpoin) {
@@ -160,55 +161,14 @@ DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
{
}
-RootDepsNode *DepsgraphNodeBuilder::add_root_node()
-{
- return m_graph->add_root_node();
-}
-
IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id)
{
return m_graph->add_id_node(id, id->name);
}
-TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source(ID *id)
+TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source()
{
- /* determine which node to attach timesource to */
- if (id) {
-#if 0 /* XXX TODO */
- /* get ID node */
- IDDepsNode id_node = m_graph->find_id_node(id);
-
- /* depends on what this is... */
- switch (GS(id->name)) {
- case ID_SCE: /* Scene - Usually sequencer strip causing time remapping... */
- {
- // TODO...
- }
- break;
-
- case ID_GR: /* Group */
- {
- // TODO...
- }
- break;
-
- // XXX: time source...
-
- default: /* Unhandled */
- printf("%s(): Unhandled ID - %s \n", __func__, id->name);
- break;
- }
-#endif
- }
- else {
- /* root-node */
- RootDepsNode *root_node = m_graph->root_node;
- if (root_node) {
- return root_node->add_time_source("Time Source");
- }
- }
-
- return NULL;
+ return m_graph->add_time_source();
}
ComponentDepsNode *DepsgraphNodeBuilder::add_component_node(
@@ -224,8 +184,7 @@ ComponentDepsNode *DepsgraphNodeBuilder::add_component_node(
OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
ComponentDepsNode *comp_node,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
const char *name,
int name_tag)
@@ -234,7 +193,7 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
name,
name_tag);
if (op_node == NULL) {
- op_node = comp_node->add_operation(optype, op, opcode, name, name_tag);
+ op_node = comp_node->add_operation(op, opcode, name, name_tag);
m_graph->operations.push_back(op_node);
}
else {
@@ -252,21 +211,19 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
ID *id,
eDepsNode_Type comp_type,
const char *comp_name,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
const char *name,
int name_tag)
{
ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name);
- return add_operation_node(comp_node, optype, op, opcode, name, name_tag);
+ return add_operation_node(comp_node, op, opcode, name, name_tag);
}
OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
ID *id,
eDepsNode_Type comp_type,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
const char *name,
int name_tag)
@@ -274,7 +231,6 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
return add_operation_node(id,
comp_type,
"",
- optype,
op,
opcode,
name,
@@ -320,6 +276,23 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
/* **** Build functions for entity nodes **** */
+void DepsgraphNodeBuilder::begin_build(Main *bmain) {
+ /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
+ * created or not. This flag is being set in add_id_node(), so functions
+ * shouldn't bother with setting it, they only might query this flag when
+ * needed.
+ */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ /* XXX nested node trees are not included in tag-clearing above,
+ * so we need to do this manually.
+ */
+ FOREACH_NODETREE(bmain, nodetree, id) {
+ if (id != (ID *)nodetree) {
+ nodetree->id.tag &= ~LIB_TAG_DOIT;
+ }
+ } FOREACH_NODETREE_END
+}
+
void DepsgraphNodeBuilder::build_group(Scene *scene,
Base *base,
Group *group)
@@ -335,41 +308,6 @@ void DepsgraphNodeBuilder::build_group(Scene *scene,
}
}
-SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
-{
- /* sanity checks */
- if (!group)
- return NULL;
-
- /* create new subgraph's data */
- Depsgraph *subgraph = reinterpret_cast<Depsgraph *>(DEG_graph_new());
-
- DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph);
-
- /* add group objects */
- LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
- /*Object *ob = go->ob;*/
-
- /* Each "group object" is effectively a separate instance of the
- * underlying object data. When the group is evaluated, the transform
- * results and/or some other attributes end up getting overridden by
- * the group.
- */
- }
-
- /* Create a node for representing subgraph. */
- SubgraphDepsNode *subgraph_node = m_graph->add_subgraph_node(&group->id);
- subgraph_node->graph = subgraph;
-
- /* Make a copy of the data this node will need? */
- /* XXX: do we do this now, or later? */
- /* TODO: need API function which queries graph's ID's hash, and duplicates
- * those blocks thoroughly with all outside links removed.
- */
-
- return subgraph_node;
-}
-
void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
{
const bool has_object = (ob->id.tag & LIB_TAG_DOIT);
@@ -383,8 +321,11 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
if (base != NULL) {
id_node->layers |= base->lay;
}
- if (ob == scene->camera) {
- /* Camera should always be updated, it used directly by viewport. */
+ if (ob->type == OB_CAMERA) {
+ /* Camera should always be updated, it used directly by viewport.
+ *
+ * TODO(sergey): Make it only for active scene camera.
+ */
id_node->layers |= (unsigned int)(-1);
}
/* Skip rest of components if the ID node was already there. */
@@ -410,12 +351,11 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
BuilderWalkUserData data;
data.builder = this;
data.scene = scene;
- modifiers_foreachObjectLink(ob, modifier_walk, &data);
BKE_constraints_id_loop(&ob->constraints, constraint_walk, &data);
}
/* Object data. */
- if (ob->data) {
+ if (ob->data != NULL) {
/* type-specific data... */
switch (ob->type) {
case OB_MESH: /* Geometry */
@@ -473,27 +413,41 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
build_animdata(&ob->id);
/* particle systems */
- if (ob->particlesystem.first) {
+ if (ob->particlesystem.first != NULL) {
build_particles(scene, ob);
}
- /* grease pencil */
- if (ob->gpd) {
+ /* Grease pencil. */
+ if (ob->gpd != NULL) {
build_gpencil(ob->gpd);
}
+
+ /* Object that this is a proxy for. */
+ if (ob->proxy) {
+ ob->proxy->proxy_from = ob;
+ build_object(scene, base, ob->proxy);
+ }
+
+ /* Object dupligroup. */
+ if (ob->dup_group != NULL) {
+ build_group(scene, base, ob->dup_group);
+ }
}
void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
{
+ OperationDepsNode *op_node;
+
/* local transforms (from transform channels - loc/rot/scale + deltas) */
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_INIT, function_bind(BKE_object_eval_local_transform, _1, scene, ob),
- DEG_OPCODE_TRANSFORM_LOCAL);
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_object_eval_local_transform, _1, scene, ob),
+ DEG_OPCODE_TRANSFORM_LOCAL);
+ op_node->set_as_entry();
/* object parent */
if (ob->parent) {
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_parent, _1, scene, ob),
+ add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_object_eval_parent, _1, scene, ob),
DEG_OPCODE_TRANSFORM_PARENT);
}
@@ -509,14 +463,15 @@ void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
*
* TODO(sergey): Get rid of this node.
*/
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_uber_transform, _1, scene, ob),
+ add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_object_eval_uber_transform, _1, scene, ob),
DEG_OPCODE_OBJECT_UBEREVAL);
/* object transform is done */
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_POST, function_bind(BKE_object_eval_done, _1, ob),
- DEG_OPCODE_TRANSFORM_FINAL);
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_object_eval_done, _1, ob),
+ DEG_OPCODE_TRANSFORM_FINAL);
+ op_node->set_as_exit();
}
/**
@@ -539,8 +494,8 @@ void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob)
{
/* create node for constraint stack */
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_constraints, _1, scene, ob),
+ add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_object_eval_constraints, _1, scene, ob),
DEG_OPCODE_TRANSFORM_CONSTRAINTS);
}
@@ -562,8 +517,8 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
/* actions and NLA - as a single unit for now, as it gets complicated to schedule otherwise */
if ((adt->action) || (adt->nla_tracks.first)) {
/* create the node */
- add_operation_node(id, DEPSNODE_TYPE_ANIMATION,
- DEPSOP_TYPE_EXEC, function_bind(BKE_animsys_eval_animdata, _1, id),
+ add_operation_node(id, DEG_NODE_TYPE_ANIMATION,
+ function_bind(BKE_animsys_eval_animdata, _1, id),
DEG_OPCODE_ANIMATION, id->name);
// TODO: for each channel affected, we might also want to add some support for running RNA update callbacks on them
@@ -593,18 +548,17 @@ OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
* and use some tagging magic instead.
*/
OperationDepsNode *driver_op = find_operation_node(id,
- DEPSNODE_TYPE_PARAMETERS,
+ DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_DRIVER,
- fcu->rna_path,
+ fcu->rna_path ? fcu->rna_path : "",
fcu->array_index);
if (driver_op == NULL) {
driver_op = add_operation_node(id,
- DEPSNODE_TYPE_PARAMETERS,
- DEPSOP_TYPE_EXEC,
+ DEG_NODE_TYPE_PARAMETERS,
function_bind(BKE_animsys_eval_driver, _1, id, fcu),
DEG_OPCODE_DRIVER,
- fcu->rna_path,
+ fcu->rna_path ? fcu->rna_path : "",
fcu->array_index);
}
@@ -625,19 +579,20 @@ void DepsgraphNodeBuilder::build_world(World *world)
return;
}
- /* world itself */
- IDDepsNode *world_node = add_id_node(world_id); /* world shading/params? */
-
build_animdata(world_id);
- /* TODO: other settings? */
+ /* world itself */
+ add_component_node(world_id, DEG_NODE_TYPE_PARAMETERS);
+
+ add_operation_node(world_id, DEG_NODE_TYPE_PARAMETERS, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
/* textures */
- build_texture_stack(world_node, world->mtex);
+ build_texture_stack(world->mtex);
/* world's nodetree */
if (world->nodetree) {
- build_nodetree(world_node, world->nodetree);
+ build_nodetree(world->nodetree);
}
}
@@ -665,14 +620,14 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
/* XXX: is this the right component, or do we want to use another one instead? */
/* init/rebuild operation */
- /*OperationDepsNode *init_node =*/ add_operation_node(&scene->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_REBUILD, function_bind(BKE_rigidbody_rebuild_sim, _1, scene),
+ /*OperationDepsNode *init_node =*/ add_operation_node(&scene->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_rigidbody_rebuild_sim, _1, scene),
DEG_OPCODE_RIGIDBODY_REBUILD);
/* do-sim operation */
// XXX: what happens if we need to split into several groups?
- OperationDepsNode *sim_node = add_operation_node(&scene->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_SIM, function_bind(BKE_rigidbody_eval_simulation, _1, scene),
+ OperationDepsNode *sim_node = add_operation_node(&scene->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_rigidbody_eval_simulation, _1, scene),
DEG_OPCODE_RIGIDBODY_SIM);
/* XXX: For now, the sim node is the only one that really matters here. If any other
@@ -692,8 +647,8 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
/* 2) create operation for flushing results */
/* object's transform component - where the rigidbody operation lives */
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_EXEC, function_bind(BKE_rigidbody_object_sync_transforms, _1, scene, ob),
+ add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_rigidbody_object_sync_transforms, _1, scene, ob),
DEG_OPCODE_TRANSFORM_RIGIDBODY);
}
}
@@ -717,7 +672,15 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
*/
/* component for all particle systems */
- ComponentDepsNode *psys_comp = add_component_node(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES);
+ ComponentDepsNode *psys_comp =
+ add_component_node(&ob->id, DEG_NODE_TYPE_EVAL_PARTICLES);
+
+ add_operation_node(psys_comp,
+ function_bind(BKE_particle_system_eval_init,
+ _1,
+ scene,
+ ob),
+ DEG_OPCODE_PSYS_EVAL_INIT);
/* particle systems */
LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
@@ -730,11 +693,7 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
/* this particle system */
// TODO: for now, this will just be a placeholder "ubereval" node
add_operation_node(psys_comp,
- DEPSOP_TYPE_EXEC, function_bind(BKE_particle_system_eval,
- _1,
- scene,
- ob,
- psys),
+ NULL,
DEG_OPCODE_PSYS_EVAL,
psys->name);
}
@@ -743,12 +702,25 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
// TODO...
}
+void DepsgraphNodeBuilder::build_cloth(Scene *scene, Object *object)
+{
+ ComponentDepsNode *cache_comp = add_component_node(&object->id,
+ DEG_NODE_TYPE_CACHE);
+ add_operation_node(cache_comp,
+ function_bind(BKE_object_eval_cloth,
+ _1,
+ scene,
+ object),
+ DEG_OPCODE_PLACEHOLDER,
+ "Cloth Modifier");
+}
+
/* Shapekeys */
void DepsgraphNodeBuilder::build_shapekeys(Key *key)
{
build_animdata(&key->id);
- add_operation_node(&key->id, DEPSNODE_TYPE_GEOMETRY, DEPSOP_TYPE_EXEC, NULL,
+ add_operation_node(&key->id, DEG_NODE_TYPE_GEOMETRY, NULL,
DEG_OPCODE_PLACEHOLDER, "Shapekey Eval");
}
@@ -757,18 +729,19 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
{
ID *obdata = (ID *)ob->data;
+ OperationDepsNode *op_node;
/* TODO(sergey): This way using this object's properties as driver target
* works fine.
*
* Does this depend on other nodes?
*/
- add_operation_node(&ob->id,
- DEPSNODE_TYPE_PARAMETERS,
- DEPSOP_TYPE_POST,
- NULL,
- DEG_OPCODE_PLACEHOLDER,
- "Parameters Eval");
+ op_node = add_operation_node(&ob->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Parameters Eval");
+ op_node->set_as_exit();
/* Temporary uber-update node, which does everything.
* It is for the being we're porting old dependencies into the new system.
@@ -777,42 +750,33 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
*
* TODO(sergey): Get rid of this node.
*/
- add_operation_node(&ob->id,
- DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_POST,
- function_bind(BKE_object_eval_uber_data, _1, scene, ob),
- DEG_OPCODE_GEOMETRY_UBEREVAL);
-
- add_operation_node(&ob->id,
- DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT,
- NULL,
- DEG_OPCODE_PLACEHOLDER,
- "Eval Init");
+ op_node = add_operation_node(&ob->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_object_eval_uber_data, _1, scene, ob),
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+ op_node->set_as_exit();
+
+ op_node = add_operation_node(&ob->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Eval Init");
+ op_node->set_as_entry();
// TODO: "Done" operation
- /* Modifiers */
+ /* Cloyth modifier. */
LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) {
- add_operation_node(&ob->id,
- DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_EXEC,
- function_bind(BKE_object_eval_modifier,
- _1,
- scene,
- ob,
- md),
- DEG_OPCODE_GEOMETRY_MODIFIER,
- md->name);
+ if (md->type == eModifierType_Cloth) {
+ build_cloth(scene, ob);
+ }
}
/* materials */
for (int a = 1; a <= ob->totcol; a++) {
Material *ma = give_current_material(ob, a);
if (ma != NULL) {
- // XXX?!
- ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
- build_material(geom_node, ma);
+ build_material(ma);
}
}
@@ -842,14 +806,14 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
//Mesh *me = (Mesh *)ob->data;
/* evaluation operations */
- add_operation_node(obdata,
- DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT,
- function_bind(BKE_mesh_eval_geometry,
- _1,
- (Mesh *)obdata),
- DEG_OPCODE_PLACEHOLDER,
- "Geometry Eval");
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_mesh_eval_geometry,
+ _1,
+ (Mesh *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
break;
}
@@ -861,14 +825,14 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
if (mom == ob) {
/* metaball evaluation operations */
/* NOTE: only the motherball gets evaluated! */
- add_operation_node(obdata,
- DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT,
- function_bind(BKE_mball_eval_geometry,
- _1,
- (MetaBall *)obdata),
- DEG_OPCODE_PLACEHOLDER,
- "Geometry Eval");
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_mball_eval_geometry,
+ _1,
+ (MetaBall *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
}
break;
}
@@ -879,26 +843,14 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
{
/* Curve/nurms evaluation operations. */
/* - calculate curve geometry (including path) */
- add_operation_node(obdata,
- DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT,
- function_bind(BKE_curve_eval_geometry,
- _1,
- (Curve *)obdata),
- DEG_OPCODE_PLACEHOLDER,
- "Geometry Eval");
-
- /* Calculate curve path - this is used by constraints, etc. */
- if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
- add_operation_node(obdata,
- DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_EXEC,
- function_bind(BKE_curve_eval_path,
- _1,
- (Curve *)obdata),
- DEG_OPCODE_GEOMETRY_PATH,
- "Path");
- }
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_curve_eval_geometry,
+ _1,
+ (Curve *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
/* Make sure objects used for bevel.taper are in the graph.
* NOTE: This objects might be not linked to the scene.
@@ -919,24 +871,24 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
case OB_LATTICE:
{
/* Lattice evaluation operations. */
- add_operation_node(obdata,
- DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT,
- function_bind(BKE_lattice_eval_geometry,
- _1,
- (Lattice *)obdata),
- DEG_OPCODE_PLACEHOLDER,
- "Geometry Eval");
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_lattice_eval_geometry,
+ _1,
+ (Lattice *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
break;
}
}
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_POST, NULL,
- DEG_OPCODE_PLACEHOLDER, "Eval Done");
+ op_node = add_operation_node(obdata, DEG_NODE_TYPE_GEOMETRY, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Eval Done");
+ op_node->set_as_exit();
/* Parameters for driver sources. */
- add_operation_node(obdata, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ add_operation_node(obdata, DEG_NODE_TYPE_PARAMETERS, NULL,
DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
}
@@ -952,15 +904,13 @@ void DepsgraphNodeBuilder::build_camera(Object *ob)
build_animdata(&cam->id);
- add_operation_node(camera_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ add_operation_node(camera_id, DEG_NODE_TYPE_PARAMETERS, NULL,
DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
if (cam->dof_ob != NULL) {
/* TODO(sergey): For now parametrs are on object level. */
- add_operation_node(&ob->id, DEPSNODE_TYPE_PARAMETERS,
- DEPSOP_TYPE_EXEC, NULL,
- DEG_OPCODE_PLACEHOLDER,
- "Camera DOF");
+ add_operation_node(&ob->id, DEG_NODE_TYPE_PARAMETERS, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Camera DOF");
}
}
@@ -976,45 +926,47 @@ void DepsgraphNodeBuilder::build_lamp(Object *ob)
build_animdata(&la->id);
/* node for obdata */
- ComponentDepsNode *param_node = add_component_node(lamp_id, DEPSNODE_TYPE_PARAMETERS);
+ add_component_node(lamp_id, DEG_NODE_TYPE_PARAMETERS);
/* TODO(sergey): Is it really how we're supposed to work with drivers? */
- add_operation_node(lamp_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ add_operation_node(lamp_id, DEG_NODE_TYPE_PARAMETERS, NULL,
DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
/* lamp's nodetree */
if (la->nodetree) {
- build_nodetree(param_node, la->nodetree);
+ build_nodetree(la->nodetree);
}
/* textures */
- build_texture_stack(param_node, la->mtex);
+ build_texture_stack(la->mtex);
}
-void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree)
+void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
{
if (!ntree)
return;
/* nodetree itself */
ID *ntree_id = &ntree->id;
+ OperationDepsNode *op_node;
build_animdata(ntree_id);
/* Parameters for drivers. */
- add_operation_node(ntree_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_POST, NULL,
- DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+ op_node = add_operation_node(ntree_id, DEG_NODE_TYPE_PARAMETERS, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+ op_node->set_as_exit();
/* nodetree's nodes... */
LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
ID *id = bnode->id;
if (id != NULL) {
- short id_type = GS(id->name);
+ ID_Type id_type = GS(id->name);
if (id_type == ID_MA) {
- build_material(owner_node, (Material *)id);
+ build_material((Material *)id);
}
else if (id_type == ID_TE) {
- build_texture(owner_node, (Tex *)id);
+ build_texture((Tex *)id);
}
else if (id_type == ID_IM) {
build_image((Image *)id);
@@ -1022,7 +974,7 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree
else if (bnode->type == NODE_GROUP) {
bNodeTree *group_ntree = (bNodeTree *)id;
if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
- build_nodetree(owner_node, group_ntree);
+ build_nodetree(group_ntree);
}
}
}
@@ -1032,7 +984,7 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree
}
/* Recursively build graph for material */
-void DepsgraphNodeBuilder::build_material(DepsNode *owner_node, Material *ma)
+void DepsgraphNodeBuilder::build_material(Material *ma)
{
ID *ma_id = &ma->id;
if (ma_id->tag & LIB_TAG_DOIT) {
@@ -1042,22 +994,21 @@ void DepsgraphNodeBuilder::build_material(DepsNode *owner_node, Material *ma)
/* material itself */
add_id_node(ma_id);
- add_operation_node(ma_id, DEPSNODE_TYPE_SHADING,
- DEPSOP_TYPE_EXEC, NULL,
+ add_operation_node(ma_id, DEG_NODE_TYPE_SHADING, NULL,
DEG_OPCODE_PLACEHOLDER, "Material Update");
/* material animation */
build_animdata(ma_id);
/* textures */
- build_texture_stack(owner_node, ma->mtex);
+ build_texture_stack(ma->mtex);
/* material's nodetree */
- build_nodetree(owner_node, ma->nodetree);
+ build_nodetree(ma->nodetree);
}
/* Texture-stack attached to some shading datablock */
-void DepsgraphNodeBuilder::build_texture_stack(DepsNode *owner_node, MTex **texture_stack)
+void DepsgraphNodeBuilder::build_texture_stack(MTex **texture_stack)
{
int i;
@@ -1065,12 +1016,12 @@ void DepsgraphNodeBuilder::build_texture_stack(DepsNode *owner_node, MTex **text
for (i = 0; i < MAX_MTEX; i++) {
MTex *mtex = texture_stack[i];
if (mtex && mtex->tex)
- build_texture(owner_node, mtex->tex);
+ build_texture(mtex->tex);
}
}
/* Recursively build graph for texture */
-void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex)
+void DepsgraphNodeBuilder::build_texture(Tex *tex)
{
ID *tex_id = &tex->id;
if (tex_id->tag & LIB_TAG_DOIT) {
@@ -1080,7 +1031,7 @@ void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex)
/* Texture itself. */
build_animdata(tex_id);
/* Texture's nodetree. */
- build_nodetree(owner_node, tex->nodetree);
+ build_nodetree(tex->nodetree);
/* Special cases for different IDs which texture uses. */
if (tex->type == TEX_IMAGE) {
if (tex->ima != NULL) {
@@ -1099,8 +1050,7 @@ void DepsgraphNodeBuilder::build_image(Image *image) {
add_id_node(image_id);
/* Placeholder so we can add relations and tag ID node for update. */
add_operation_node(image_id,
- DEPSNODE_TYPE_PARAMETERS,
- DEPSOP_TYPE_EXEC,
+ DEG_NODE_TYPE_PARAMETERS,
NULL,
DEG_OPCODE_PLACEHOLDER,
"Image Eval");
@@ -1111,11 +1061,11 @@ void DepsgraphNodeBuilder::build_compositor(Scene *scene)
/* For now, just a plain wrapper? */
// TODO: create compositing component?
// XXX: component type undefined!
- //graph->get_node(&scene->id, NULL, DEPSNODE_TYPE_COMPOSITING, NULL);
+ //graph->get_node(&scene->id, NULL, DEG_NODE_TYPE_COMPOSITING, NULL);
/* for now, nodetrees are just parameters; compositing occurs in internals of renderer... */
- ComponentDepsNode *owner_node = add_component_node(&scene->id, DEPSNODE_TYPE_PARAMETERS);
- build_nodetree(owner_node, scene->nodetree);
+ add_component_node(&scene->id, DEG_NODE_TYPE_PARAMETERS);
+ build_nodetree(scene->nodetree);
}
void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
@@ -1136,9 +1086,8 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
{
ID *cache_file_id = &cache_file->id;
- add_component_node(cache_file_id, DEPSNODE_TYPE_CACHE);
- add_operation_node(cache_file_id, DEPSNODE_TYPE_CACHE,
- DEPSOP_TYPE_EXEC, NULL,
+ add_component_node(cache_file_id, DEG_NODE_TYPE_CACHE);
+ add_operation_node(cache_file_id, DEG_NODE_TYPE_CACHE, NULL,
DEG_OPCODE_PLACEHOLDER, "Cache File Update");
add_id_node(cache_file_id);
@@ -1149,7 +1098,18 @@ void DepsgraphNodeBuilder::build_mask(Mask *mask)
{
ID *mask_id = &mask->id;
add_id_node(mask_id);
+ /* F-Curve based animation/ */
build_animdata(mask_id);
+ /* Animation based on mask's shapes. */
+ add_operation_node(mask_id,
+ DEG_NODE_TYPE_ANIMATION,
+ function_bind(BKE_mask_eval_animation, _1, mask),
+ DEG_OPCODE_MASK_ANIMATION);
+ /* Final mask evaluation. */
+ add_operation_node(mask_id,
+ DEG_NODE_TYPE_PARAMETERS,
+ function_bind(BKE_mask_eval_update, _1, mask),
+ DEG_OPCODE_MASK_EVAL);
}
void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 9cb8bc5d45c..a54b1c76c77 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -61,8 +61,6 @@ namespace DEG {
struct Depsgraph;
struct DepsNode;
-struct RootDepsNode;
-struct SubgraphDepsNode;
struct IDDepsNode;
struct TimeSourceDepsNode;
struct ComponentDepsNode;
@@ -72,32 +70,30 @@ struct DepsgraphNodeBuilder {
DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
~DepsgraphNodeBuilder();
- RootDepsNode *add_root_node();
+ void begin_build(Main *bmain);
+
IDDepsNode *add_id_node(ID *id);
- TimeSourceDepsNode *add_time_source(ID *id);
+ TimeSourceDepsNode *add_time_source();
ComponentDepsNode *add_component_node(ID *id,
eDepsNode_Type comp_type,
const char *comp_name = "");
OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
const char *name = "",
int name_tag = -1);
OperationDepsNode *add_operation_node(ID *id,
eDepsNode_Type comp_type,
const char *comp_name,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
const char *name = "",
int name_tag = -1);
OperationDepsNode *add_operation_node(ID *id,
eDepsNode_Type comp_type,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
const char *name = "",
int name_tag = -1);
@@ -123,14 +119,14 @@ struct DepsgraphNodeBuilder {
int name_tag = -1);
void build_scene(Main *bmain, Scene *scene);
- SubgraphDepsNode *build_subgraph(Group *group);
void build_group(Scene *scene, Base *base, Group *group);
void build_object(Scene *scene, Base *base, Object *ob);
void build_object_transform(Scene *scene, Object *ob);
void build_object_constraints(Scene *scene, Object *ob);
- void build_pose_constraints(Object *ob, bPoseChannel *pchan);
+ void build_pose_constraints(Scene *scene, Object *ob, bPoseChannel *pchan);
void build_rigidbody(Scene *scene);
void build_particles(Scene *scene, Object *ob);
+ void build_cloth(Scene *scene, Object *object);
void build_animdata(ID *id);
OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
void build_ik_pose(Scene *scene,
@@ -147,10 +143,10 @@ struct DepsgraphNodeBuilder {
void build_obdata_geom(Scene *scene, Object *ob);
void build_camera(Object *ob);
void build_lamp(Object *ob);
- void build_nodetree(DepsNode *owner_node, bNodeTree *ntree);
- void build_material(DepsNode *owner_node, Material *ma);
- void build_texture(DepsNode *owner_node, Tex *tex);
- void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
+ void build_nodetree(bNodeTree *ntree);
+ void build_material(Material *ma);
+ void build_texture(Tex *tex);
+ void build_texture_stack(MTex **texture_stack);
void build_image(Image *image);
void build_world(World *world);
void build_compositor(Scene *scene);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index 4a5f3dc8664..ceb2fd25f94 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -37,11 +37,11 @@
#include "MEM_guardedalloc.h"
-extern "C" {
+#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_string.h"
-#include "BLI_utildefines.h"
+extern "C" {
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
@@ -49,10 +49,10 @@ extern "C" {
#include "BKE_action.h"
#include "BKE_armature.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-} /* extern "C" */
#include "intern/builder/deg_builder.h"
#include "intern/nodes/deg_node.h"
@@ -64,11 +64,11 @@ extern "C" {
namespace DEG {
-void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan)
+void DepsgraphNodeBuilder::build_pose_constraints(Scene *scene, Object *ob, bPoseChannel *pchan)
{
/* create node for constraint stack */
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan),
+ add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+ function_bind(BKE_pose_constraints_evaluate, _1, scene, ob, pchan),
DEG_OPCODE_BONE_CONSTRAINTS);
}
@@ -80,15 +80,15 @@ void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel
/* Find the chain's root. */
bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
- if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
+ if (has_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
DEG_OPCODE_POSE_IK_SOLVER))
{
return;
}
/* Operation node for evaluating/running IK Solver. */
- add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
- DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
+ add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
+ function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
DEG_OPCODE_POSE_IK_SOLVER);
}
@@ -103,8 +103,8 @@ void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseCh
/* Operation node for evaluating/running Spline IK Solver.
* Store the "root bone" of this chain in the solver, so it knows where to start.
*/
- add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
- DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
+ add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
+ function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
}
@@ -112,6 +112,7 @@ void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseCh
void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
{
bArmature *arm = (bArmature *)ob->data;
+ OperationDepsNode *op_node;
/* animation and/or drivers linking posebones to base-armature used to define them
* NOTE: AnimData here is really used to control animated deform properties,
@@ -119,7 +120,16 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
* Eventually, we need some type of proxy/isolation mechanism in-between here
* to ensure that we can use same rig multiple times in same scene...
*/
- build_animdata(&arm->id);
+ if ((arm->id.tag & LIB_TAG_DOIT) == 0) {
+ build_animdata(&arm->id);
+
+ /* Make sure pose is up-to-date with armature updates. */
+ add_operation_node(&arm->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Armature Eval");
+ }
/* Rebuild pose if not up to date. */
if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
@@ -141,14 +151,6 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
}
}
- /* Make sure pose is up-to-date with armature updates. */
- add_operation_node(&arm->id,
- DEPSNODE_TYPE_PARAMETERS,
- DEPSOP_TYPE_EXEC,
- NULL,
- DEG_OPCODE_PLACEHOLDER,
- "Armature Eval");
-
/**
* Pose Rig Graph
* ==============
@@ -172,34 +174,46 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
*/
/* pose eval context */
- add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
- DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT);
-
- add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
- DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE);
+ op_node = add_operation_node(&ob->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose),
+ DEG_OPCODE_POSE_INIT);
+ op_node->set_as_entry();
+
+ op_node = add_operation_node(&ob->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ function_bind(BKE_pose_eval_init_ik, _1, scene, ob, ob->pose),
+ DEG_OPCODE_POSE_INIT_IK);
+
+ op_node = add_operation_node(&ob->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose),
+ DEG_OPCODE_POSE_DONE);
+ op_node->set_as_exit();
/* bones */
LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
/* node for bone eval */
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local
- DEG_OPCODE_BONE_LOCAL);
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, NULL,
+ DEG_OPCODE_BONE_LOCAL);
+ op_node->set_as_entry();
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose
+ add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+ function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan),
DEG_OPCODE_BONE_POSE_PARENT);
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */
+ add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+ NULL, /* NOTE: dedicated noop for easier relationship construction */
DEG_OPCODE_BONE_READY);
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan),
- DEG_OPCODE_BONE_DONE);
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+ function_bind(BKE_pose_bone_done, _1, pchan),
+ DEG_OPCODE_BONE_DONE);
+ op_node->set_as_exit();
/* constraints */
if (pchan->constraints.first != NULL) {
- build_pose_constraints(ob, pchan);
+ build_pose_constraints(scene, ob, pchan);
}
/**
@@ -233,6 +247,8 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
{
ID *obdata = (ID *)ob->data;
+ OperationDepsNode *op_node;
+
build_animdata(obdata);
BLI_assert(ob->pose != NULL);
@@ -243,31 +259,28 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
BKE_pose_update_constraint_flags(ob->pose);
}
- add_operation_node(&ob->id,
- DEPSNODE_TYPE_EVAL_POSE,
- DEPSOP_TYPE_INIT,
- function_bind(BKE_pose_eval_proxy_copy, _1, ob),
- DEG_OPCODE_POSE_INIT);
+ op_node = add_operation_node(&ob->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ function_bind(BKE_pose_eval_proxy_copy, _1, ob),
+ DEG_OPCODE_POSE_INIT);
+ op_node->set_as_entry();
LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_INIT, NULL,
- DEG_OPCODE_BONE_LOCAL);
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+ NULL, DEG_OPCODE_BONE_LOCAL);
+ op_node->set_as_entry();
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_EXEC, NULL,
- DEG_OPCODE_BONE_READY);
+ add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+ NULL, DEG_OPCODE_BONE_READY);
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_POST, NULL,
- DEG_OPCODE_BONE_DONE);
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+ NULL, DEG_OPCODE_BONE_DONE);
+ op_node->set_as_exit();
}
- add_operation_node(&ob->id,
- DEPSNODE_TYPE_EVAL_POSE,
- DEPSOP_TYPE_POST,
- NULL,
- DEG_OPCODE_POSE_DONE);
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE,
+ NULL, DEG_OPCODE_POSE_DONE);
+ op_node->set_as_exit();
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
index bcd4bc51448..521276bc608 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
@@ -37,21 +37,21 @@
#include "MEM_guardedalloc.h"
-extern "C" {
+#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_string.h"
-#include "BLI_utildefines.h"
+extern "C" {
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BKE_main.h"
#include "BKE_node.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-} /* extern "C" */
#include "intern/builder/deg_builder.h"
#include "intern/nodes/deg_node.h"
@@ -65,25 +65,11 @@ namespace DEG {
void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
{
- /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
- * created or not. This flag is being set in add_id_node(), so functions
- * shouldn't bother with setting it, they only might query this flag when
- * needed.
- */
- BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- /* XXX nested node trees are not included in tag-clearing above,
- * so we need to do this manually.
- */
- FOREACH_NODETREE(bmain, nodetree, id) {
- if (id != (ID *)nodetree)
- nodetree->id.tag &= ~LIB_TAG_DOIT;
- } FOREACH_NODETREE_END
-
/* scene ID block */
add_id_node(&scene->id);
/* timesource */
- add_time_source(NULL);
+ add_time_source();
/* build subgraph for set, and link this in... */
// XXX: depending on how this goes, that scene itself could probably store its
@@ -95,21 +81,7 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
/* scene objects */
LINKLIST_FOREACH (Base *, base, &scene->base) {
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 dupligroup. */
- if (ob->dup_group) {
- build_group(scene, base, ob->dup_group);
- }
}
/* rigidbody */
@@ -154,6 +126,13 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
LINKLIST_FOREACH (MovieClip *, clip, &bmain->movieclip) {
build_movieclip(clip);
}
+
+ /* Parameters evaluation for scene relations mainly. */
+ add_operation_node(&scene->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Scene Eval");
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index f870a33fb68..59eb7ed8cf1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -33,10 +33,8 @@
#include <stdio.h>
#include <string.h>
-extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
-}
namespace DEG {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index dadb7f8917f..d42c4047691 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -38,10 +38,10 @@
#include "MEM_guardedalloc.h"
-extern "C" {
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_blenlib.h"
+extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -92,13 +92,13 @@ extern "C" {
#include "BKE_tracking.h"
#include "BKE_world.h"
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-
#include "RNA_access.h"
#include "RNA_types.h"
} /* extern "C" */
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "intern/builder/deg_builder.h"
#include "intern/builder/deg_builder_pchanmap.h"
@@ -113,6 +113,41 @@ extern "C" {
namespace DEG {
+namespace {
+
+struct BuilderWalkUserData {
+ DepsgraphRelationBuilder *builder;
+ Main *bmain;
+ Scene *scene;
+};
+
+static void modifier_walk(void *user_data,
+ struct Object * /*ob*/,
+ struct Object **obpoin,
+ int /*cb_flag*/)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ if (*obpoin) {
+ data->builder->build_object(data->bmain, data->scene, *obpoin);
+ }
+}
+
+void constraint_walk(bConstraint * /*con*/,
+ ID **idpoin,
+ bool /*is_reference*/,
+ void *user_data)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ if (*idpoin) {
+ ID *id = *idpoin;
+ if (GS(id->name) == ID_OB) {
+ data->builder->build_object(data->bmain, data->scene, (Object *)id);
+ }
+ }
+}
+
+} /* namespace */
+
/* ***************** */
/* Relations Builder */
@@ -129,8 +164,8 @@ static bool python_driver_depends_on_time(ChannelDriver *driver)
/* Function calls are considered dependent on a time. */
return true;
}
- if (strstr(driver->expression, "time") != NULL) {
- /* Variable `time` depends on time. */
+ if (strstr(driver->expression, "frame") != NULL) {
+ /* Variable `frame` depends on time. */
/* TODO(sergey): This is a bit weak, but not sure about better way of
* handling this.
*/
@@ -163,13 +198,6 @@ DepsgraphRelationBuilder::DepsgraphRelationBuilder(Depsgraph *graph) :
{
}
-RootDepsNode *DepsgraphRelationBuilder::find_node(const RootKey &key) const
-{
- (void)key;
- BLI_assert(!"Doesn't seem to be correct");
- return m_graph->root_node;
-}
-
TimeSourceDepsNode *DepsgraphRelationBuilder::find_node(
const TimeSourceKey &key) const
{
@@ -178,7 +206,7 @@ TimeSourceDepsNode *DepsgraphRelationBuilder::find_node(
return NULL;
}
else {
- return m_graph->root_node->time_source;
+ return m_graph->time_source;
}
}
@@ -247,7 +275,7 @@ void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
const char *description)
{
if (timesrc && node_to) {
- m_graph->add_new_relation(timesrc, node_to, DEPSREL_TYPE_TIME, description);
+ m_graph->add_new_relation(timesrc, node_to, description);
}
else {
DEG_DEBUG_PRINTF("add_time_relation(%p = %s, %p = %s, %s) Failed\n",
@@ -260,17 +288,16 @@ void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
void DepsgraphRelationBuilder::add_operation_relation(
OperationDepsNode *node_from,
OperationDepsNode *node_to,
- eDepsRelation_Type type,
const char *description)
{
if (node_from && node_to) {
- m_graph->add_new_relation(node_from, node_to, type, description);
+ m_graph->add_new_relation(node_from, node_to, description);
}
else {
- DEG_DEBUG_PRINTF("add_operation_relation(%p = %s, %p = %s, %d, %s) Failed\n",
+ DEG_DEBUG_PRINTF("add_operation_relation(%p = %s, %p = %s, %s) Failed\n",
node_from, (node_from) ? node_from->identifier().c_str() : "<None>",
node_to, (node_to) ? node_to->identifier().c_str() : "<None>",
- type, description);
+ description);
}
}
@@ -283,11 +310,11 @@ void DepsgraphRelationBuilder::add_collision_relations(const OperationKey &key,
{
Object *ob1 = collobjs[i];
- ComponentKey trf_key(&ob1->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(trf_key, key, DEPSREL_TYPE_STANDARD, name);
+ ComponentKey trf_key(&ob1->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(trf_key, key, name);
- ComponentKey coll_key(&ob1->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(coll_key, key, DEPSREL_TYPE_STANDARD, name);
+ ComponentKey coll_key(&ob1->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(coll_key, key, name);
}
if (collobjs)
@@ -301,31 +328,31 @@ void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key,
if (effectors) {
for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
if (eff->ob != ob) {
- ComponentKey eff_key(&eff->ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(eff_key, key, DEPSREL_TYPE_STANDARD, name);
+ ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(eff_key, key, name);
}
if (eff->psys) {
if (eff->ob != ob) {
- ComponentKey eff_key(&eff->ob->id, DEPSNODE_TYPE_EVAL_PARTICLES);
- add_relation(eff_key, key, DEPSREL_TYPE_STANDARD, name);
+ ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES);
+ add_relation(eff_key, key, name);
/* TODO: remove this when/if EVAL_PARTICLES is sufficient for up to date particles */
- ComponentKey mod_key(&eff->ob->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(mod_key, key, DEPSREL_TYPE_STANDARD, name);
+ ComponentKey mod_key(&eff->ob->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(mod_key, key, name);
}
else if (eff->psys != psys) {
- OperationKey eff_key(&eff->ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, eff->psys->name);
- add_relation(eff_key, key, DEPSREL_TYPE_STANDARD, name);
+ OperationKey eff_key(&eff->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, eff->psys->name);
+ add_relation(eff_key, key, name);
}
}
if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
- ComponentKey trf_key(&eff->pd->f_source->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(trf_key, key, DEPSREL_TYPE_STANDARD, "Smoke Force Domain");
+ ComponentKey trf_key(&eff->pd->f_source->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(trf_key, key, "Smoke Force Domain");
- ComponentKey eff_key(&eff->pd->f_source->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(eff_key, key, DEPSREL_TYPE_STANDARD, "Smoke Force Domain");
+ ComponentKey eff_key(&eff->pd->f_source->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(eff_key, key, "Smoke Force Domain");
}
if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
@@ -337,8 +364,29 @@ void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key,
pdEndEffectors(&effectors);
}
+Depsgraph *DepsgraphRelationBuilder::getGraph()
+{
+ return m_graph;
+}
+
/* **** Functions to build relations between entities **** */
+void DepsgraphRelationBuilder::begin_build(Main *bmain)
+{
+ /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
+ * created or not.
+ */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ /* XXX nested node trees are notr included in tag-clearing above,
+ * so we need to do this manually.
+ */
+ FOREACH_NODETREE(bmain, nodetree, id) {
+ if (id != (ID *)nodetree) {
+ nodetree->id.tag &= ~LIB_TAG_DOIT;
+ }
+ } FOREACH_NODETREE_END
+}
+
void DepsgraphRelationBuilder::build_group(Main *bmain,
Scene *scene,
Object *object,
@@ -347,17 +395,14 @@ void DepsgraphRelationBuilder::build_group(Main *bmain,
ID *group_id = &group->id;
bool group_done = (group_id->tag & LIB_TAG_DOIT) != 0;
OperationKey object_local_transform_key(&object->id,
- DEPSNODE_TYPE_TRANSFORM,
+ DEG_NODE_TYPE_TRANSFORM,
DEG_OPCODE_TRANSFORM_LOCAL);
LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
if (!group_done) {
build_object(bmain, scene, go->ob);
}
- ComponentKey dupli_transform_key(&go->ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(dupli_transform_key,
- object_local_transform_key,
- DEPSREL_TYPE_TRANSFORM,
- "Dupligroup");
+ ComponentKey dupli_transform_key(&go->ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(dupli_transform_key, object_local_transform_key, "Dupligroup");
}
group_id->tag |= LIB_TAG_DOIT;
}
@@ -371,60 +416,85 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
/* Object Transforms */
eDepsOperation_Code base_op = (ob->parent) ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL;
- OperationKey base_op_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, base_op);
+ OperationKey base_op_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, base_op);
- OperationKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
- OperationKey parent_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
- OperationKey final_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ OperationKey local_transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
+ OperationKey parent_transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
+ OperationKey final_transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
- OperationKey ob_ubereval_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL);
+ OperationKey ob_ubereval_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL);
/* parenting */
- if (ob->parent) {
+ if (ob->parent != NULL) {
/* parent relationship */
build_object_parent(ob);
/* local -> parent */
- add_relation(local_transform_key, parent_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObLocal -> ObParent]");
+ add_relation(local_transform_key, parent_transform_key, "[ObLocal -> ObParent]");
+ }
+
+ if (ob->modifiers.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.bmain = bmain;
+ data.scene = scene;
+ modifiers_foreachObjectLink(ob, modifier_walk, &data);
+ }
+ if (ob->constraints.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.bmain = bmain;
+ data.scene = scene;
+ BKE_constraints_id_loop(&ob->constraints, constraint_walk, &data);
}
/* object constraints */
- if (ob->constraints.first) {
- OperationKey constraint_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+ if (ob->constraints.first != NULL) {
+ OperationKey constraint_key(&ob->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_CONSTRAINTS);
/* constraint relations */
// TODO: provide base op
// XXX: this is broken
- build_constraints(scene, &ob->id, DEPSNODE_TYPE_TRANSFORM, "", &ob->constraints, NULL);
+ build_constraints(scene,
+ &ob->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ "",
+ &ob->constraints,
+ NULL);
/* operation order */
- add_relation(base_op_key, constraint_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObBase-> Constraint Stack]");
- add_relation(constraint_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObConstraints -> Done]");
+ add_relation(base_op_key, constraint_key, "[ObBase-> Constraint Stack]");
+ add_relation(constraint_key, final_transform_key, "[ObConstraints -> Done]");
// XXX
- add_relation(constraint_key, ob_ubereval_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
- add_relation(ob_ubereval_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ add_relation(constraint_key, ob_ubereval_key, "Temp Ubereval");
+ add_relation(ob_ubereval_key, final_transform_key, "Temp Ubereval");
}
else {
- /* operation order */
- add_relation(base_op_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Object Transform");
-
- // XXX
- add_relation(base_op_key, ob_ubereval_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
- add_relation(ob_ubereval_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ /* NOTE: Keep an eye here, we skip some relations here to "streamline"
+ * dependencies and avoid transitive relations which causes overhead.
+ * But once we get rid of uber eval node this will need reconsideration.
+ */
+ if (ob->rigidbody_object == NULL) {
+ /* Rigid body will hook up another node inbetween, so skip
+ * relation here to avoid transitive relation.
+ */
+ add_relation(base_op_key, ob_ubereval_key, "Temp Ubereval");
+ }
+ add_relation(ob_ubereval_key, final_transform_key, "Temp Ubereval");
}
-
/* AnimData */
build_animdata(&ob->id);
// XXX: This should be hooked up by the build_animdata code
if (needs_animdata_node(&ob->id)) {
- ComponentKey adt_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
- add_relation(adt_key, local_transform_key, DEPSREL_TYPE_OPERATION, "Object Animation");
+ ComponentKey adt_key(&ob->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(adt_key, local_transform_key, "Object Animation");
}
-
/* object data */
if (ob->data) {
ID *obdata_id = (ID *)ob->data;
@@ -465,44 +535,64 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
Key *key = BKE_key_from_object(ob);
if (key != NULL) {
- ComponentKey geometry_key((ID *)ob->data, DEPSNODE_TYPE_GEOMETRY);
- ComponentKey key_key(&key->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(key_key, geometry_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Shapekeys");
+ ComponentKey geometry_key((ID *)ob->data, DEG_NODE_TYPE_GEOMETRY);
+ ComponentKey key_key(&key->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(key_key, geometry_key, "Shapekeys");
}
}
- /* particle systems */
- if (ob->particlesystem.first) {
+ /* Particle systems. */
+ if (ob->particlesystem.first != NULL) {
build_particles(scene, ob);
}
- /* grease pencil */
- if (ob->gpd) {
- build_gpencil(&ob->id, ob->gpd);
+ /* Grease pencil. */
+ if (ob->gpd != NULL) {
+ build_gpencil(ob->gpd);
+ }
+
+ /* Object that this is a proxy for. */
+ if (ob->proxy != NULL) {
+ ob->proxy->proxy_from = ob;
+ build_object(bmain, scene, ob->proxy);
+ /* TODO(sergey): This is an inverted relation, matches old depsgraph
+ * behavior and need to be investigated if it still need to be inverted.
+ */
+ ComponentKey ob_pose_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE);
+ ComponentKey proxy_pose_key(&ob->proxy->id, DEG_NODE_TYPE_EVAL_POSE);
+ add_relation(ob_pose_key, proxy_pose_key, "Proxy");
+ }
+
+ /* Object dupligroup. */
+ if (ob->dup_group != NULL) {
+ build_group(bmain, scene, ob, ob->dup_group);
}
}
void DepsgraphRelationBuilder::build_object_parent(Object *ob)
{
- /* XXX: for now, need to use the component key (not just direct to the parent op), or else the matrix doesn't get reset */
- // XXX: @sergey - it would be good if we got that backwards flushing working when tagging for updates
- //OperationKey ob_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
- ComponentKey ob_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
+ /* XXX: for now, need to use the component key (not just direct to the parent op),
+ * or else the matrix doesn't get reset/
+ */
+ // XXX: @sergey - it would be good if we got that backwards flushing working
+ // when tagging for updates.
+ //OperationKey ob_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
+ ComponentKey ob_key(&ob->id, DEG_NODE_TYPE_TRANSFORM);
/* type-specific links */
switch (ob->partype) {
case PARSKEL: /* Armature Deform (Virtual Modifier) */
{
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_STANDARD, "Armature Deform Parent");
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, "Armature Deform Parent");
break;
}
case PARVERT1: /* Vertex Parent */
case PARVERT3:
{
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Vertex Parent");
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(parent_key, ob_key, "Vertex Parent");
/* XXX not sure what this is for or how you could be done properly - lukas */
OperationDepsNode *parent_node = find_operation_node(parent_key);
@@ -510,15 +600,21 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob)
parent_node->customdata_mask |= CD_MASK_ORIGINDEX;
}
- ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Vertex Parent TFM");
+ ComponentKey transform_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(transform_key, ob_key, "Vertex Parent TFM");
break;
}
case PARBONE: /* Bone Parent */
{
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_BONE, ob->parsubstr);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Bone Parent");
+ ComponentKey parent_bone_key(&ob->parent->id,
+ DEG_NODE_TYPE_BONE,
+ ob->parsubstr);
+ OperationKey parent_transform_key(&ob->parent->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(parent_bone_key, ob_key, "Bone Parent");
+ add_relation(parent_transform_key, ob_key, "Armature Parent");
break;
}
@@ -527,33 +623,33 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob)
if (ob->parent->type == OB_LATTICE) {
/* Lattice Deform Parent - Virtual Modifier */
// XXX: no virtual modifiers should be left!
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- ComponentKey geom_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ ComponentKey geom_key(&ob->parent->id, DEG_NODE_TYPE_GEOMETRY);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_STANDARD, "Lattice Deform Parent");
- add_relation(geom_key, ob_key, DEPSREL_TYPE_STANDARD, "Lattice Deform Parent Geom");
+ add_relation(parent_key, ob_key, "Lattice Deform Parent");
+ add_relation(geom_key, ob_key, "Lattice Deform Parent Geom");
}
else if (ob->parent->type == OB_CURVE) {
Curve *cu = (Curve *)ob->parent->data;
if (cu->flag & CU_PATH) {
/* Follow Path */
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Follow Parent");
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(parent_key, ob_key, "Curve Follow Parent");
- ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Follow TFM");
+ ComponentKey transform_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(transform_key, ob_key, "Curve Follow TFM");
}
else {
/* Standard Parent */
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Parent");
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, "Curve Parent");
}
}
else {
/* Standard Parent */
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Parent");
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, "Parent");
}
break;
}
@@ -565,112 +661,149 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob)
}
}
-void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata,
- ListBase *constraints, RootPChanMap *root_map)
+void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id,
+ eDepsNode_Type component_type,
+ const char *component_subdata,
+ ListBase *constraints,
+ RootPChanMap *root_map)
{
- OperationKey constraint_op_key(id, component_type, component_subdata,
- (component_type == DEPSNODE_TYPE_BONE) ? DEG_OPCODE_BONE_CONSTRAINTS : DEG_OPCODE_TRANSFORM_CONSTRAINTS);
-
- /* add dependencies for each constraint in turn */
+ OperationKey constraint_op_key(
+ id,
+ component_type,
+ component_subdata,
+ (component_type == DEG_NODE_TYPE_BONE)
+ ? DEG_OPCODE_BONE_CONSTRAINTS
+ : DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+ /* Add dependencies for each constraint in turn. */
for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
- /* invalid constraint type... */
- if (cti == NULL)
+ /* Invalid constraint type. */
+ if (cti == NULL) {
continue;
-
- /* special case for camera tracking -- it doesn't use targets to define relations */
- // TODO: we can now represent dependencies in a much richer manner, so review how this is done...
- if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) {
+ }
+ /* Special case for camera tracking -- it doesn't use targets to
+ * define relations.
+ */
+ /* TODO: we can now represent dependencies in a much richer manner,
+ * so review how this is done.
+ */
+ if (ELEM(cti->type,
+ CONSTRAINT_TYPE_FOLLOWTRACK,
+ CONSTRAINT_TYPE_CAMERASOLVER,
+ CONSTRAINT_TYPE_OBJECTSOLVER))
+ {
bool depends_on_camera = false;
-
if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data;
-
- if (((data->clip) || (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0])
+ if (((data->clip) ||
+ (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0])
+ {
depends_on_camera = true;
-
+ }
if (data->depth_ob) {
- // DAG_RL_DATA_OB | DAG_RL_OB_OB
- ComponentKey depth_key(&data->depth_ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(depth_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ ComponentKey depth_transform_key(&data->depth_ob->id,
+ DEG_NODE_TYPE_TRANSFORM);
+ ComponentKey depth_geometry_key(&data->depth_ob->id,
+ DEG_NODE_TYPE_GEOMETRY);
+ add_relation(depth_transform_key, constraint_op_key, cti->name);
+ add_relation(depth_geometry_key, constraint_op_key, cti->name);
}
}
else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
depends_on_camera = true;
}
-
if (depends_on_camera && scene->camera) {
- // DAG_RL_DATA_OB | DAG_RL_OB_OB
- ComponentKey camera_key(&scene->camera->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(camera_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ ComponentKey camera_key(&scene->camera->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(camera_key, constraint_op_key, cti->name);
}
-
- /* TODO(sergey): This is more a TimeSource -> MovieClip -> Constraint dependency chain. */
+ /* TODO(sergey): This is more a TimeSource -> MovieClip ->
+ * Constraint dependency chain.
+ */
TimeSourceKey time_src_key;
- add_relation(time_src_key, constraint_op_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
+ add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]");
}
else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) {
- /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint dependency chain. */
+ /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint
+ * dependency chain.
+ */
TimeSourceKey time_src_key;
- add_relation(time_src_key, constraint_op_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
-
+ add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]");
bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data;
-
if (data->cache_file) {
- ComponentKey cache_key(&data->cache_file->id, DEPSNODE_TYPE_CACHE);
- add_relation(cache_key, constraint_op_key, DEPSREL_TYPE_CACHE, cti->name);
+ ComponentKey cache_key(&data->cache_file->id, DEG_NODE_TYPE_CACHE);
+ add_relation(cache_key, constraint_op_key, cti->name);
}
}
else if (cti->get_constraint_targets) {
ListBase targets = {NULL, NULL};
cti->get_constraint_targets(con, &targets);
-
LINKLIST_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == NULL) {
continue;
}
-
- if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) {
- /* ignore IK constraints - these are handled separately (on pose level) */
+ if (ELEM(con->type,
+ CONSTRAINT_TYPE_KINEMATIC,
+ CONSTRAINT_TYPE_SPLINEIK))
+ {
+ /* Ignore IK constraints - these are handled separately
+ * (on pose level).
+ */
}
- else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) {
- /* these constraints require path geometry data... */
- ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name); // XXX: type = geom_transform
- // TODO: path dependency
+ else if (ELEM(con->type,
+ CONSTRAINT_TYPE_FOLLOWPATH,
+ CONSTRAINT_TYPE_CLAMPTO))
+ {
+ /* These constraints require path geometry data. */
+ ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(target_key, constraint_op_key, cti->name);
+ ComponentKey target_transform_key(&ct->tar->id,
+ DEG_NODE_TYPE_TRANSFORM);
+ add_relation(target_transform_key, constraint_op_key, cti->name);
}
else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) {
/* bone */
if (&ct->tar->id == id) {
/* same armature */
eDepsOperation_Code target_key_opcode;
-
- /* Using "done" here breaks in-chain deps, while using "ready" here breaks most production rigs instead...
- * So, we do a compromise here, and only do this when an IK chain conflict may occur
+ /* Using "done" here breaks in-chain deps, while using
+ * "ready" here breaks most production rigs instead.
+ * So, we do a compromise here, and only do this when an
+ * IK chain conflict may occur.
*/
- if (root_map->has_common_root(component_subdata, ct->subtarget)) {
+ if (root_map->has_common_root(component_subdata,
+ ct->subtarget))
+ {
target_key_opcode = DEG_OPCODE_BONE_READY;
}
else {
target_key_opcode = DEG_OPCODE_BONE_DONE;
}
-
- OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_BONE, ct->subtarget, target_key_opcode);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ OperationKey target_key(&ct->tar->id,
+ DEG_NODE_TYPE_BONE,
+ ct->subtarget,
+ target_key_opcode);
+ add_relation(target_key, constraint_op_key, cti->name);
}
else {
- /* different armature - we can safely use the result of that */
- OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_BONE, ct->subtarget, DEG_OPCODE_BONE_DONE);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ /* Different armature - we can safely use the result
+ * of that.
+ */
+ OperationKey target_key(&ct->tar->id,
+ DEG_NODE_TYPE_BONE,
+ ct->subtarget,
+ DEG_OPCODE_BONE_DONE);
+ add_relation(target_key, constraint_op_key, cti->name);
}
}
- else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) {
- /* vertex group */
- /* NOTE: for now, we don't need to represent vertex groups separately... */
- ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name);
-
+ else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) &&
+ (ct->subtarget[0]))
+ {
+ /* Vertex group. */
+ /* NOTE: for now, we don't need to represent vertex groups
+ * separately.
+ */
+ ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(target_key, constraint_op_key, cti->name);
if (ct->tar->type == OB_MESH) {
OperationDepsNode *node2 = find_operation_node(target_key);
if (node2 != NULL) {
@@ -680,39 +813,50 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
}
else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) {
/* Constraints which requires the target object surface. */
- ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
-
- /* NOTE: obdata eval now doesn't necessarily depend on the object's transform... */
- ComponentKey target_transform_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(target_transform_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(target_key, constraint_op_key, cti->name);
+ /* NOTE: obdata eval now doesn't necessarily depend on the
+ * object's transform.
+ */
+ ComponentKey target_transform_key(&ct->tar->id,
+ DEG_NODE_TYPE_TRANSFORM);
+ add_relation(target_transform_key, constraint_op_key, cti->name);
}
else {
- /* standard object relation */
+ /* Standard object relation. */
// TODO: loc vs rot vs scale?
if (&ct->tar->id == id) {
/* Constraint targetting own object:
- * - This case is fine IFF we're dealing with a bone constraint pointing to
- * its own armature. In that case, it's just transform -> bone.
- * - If however it is a real self targetting case, just make it depend on the
- * previous constraint (or the pre-constraint state)...
+ * - This case is fine IFF we're dealing with a bone
+ * constraint pointing to its own armature. In that
+ * case, it's just transform -> bone.
+ * - If however it is a real self targetting case, just
+ * make it depend on the previous constraint (or the
+ * pre-constraint state).
*/
- if ((ct->tar->type == OB_ARMATURE) && (component_type == DEPSNODE_TYPE_BONE)) {
- OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ if ((ct->tar->type == OB_ARMATURE) &&
+ (component_type == DEG_NODE_TYPE_BONE))
+ {
+ OperationKey target_key(&ct->tar->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, constraint_op_key, cti->name);
}
else {
- OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ OperationKey target_key(&ct->tar->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_LOCAL);
+ add_relation(target_key, constraint_op_key, cti->name);
}
}
else {
- /* normal object dependency */
- OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ /* Normal object dependency. */
+ OperationKey target_key(&ct->tar->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, constraint_op_key, cti->name);
}
}
-
/* Constraints which needs world's matrix for transform.
* TODO(sergey): More constraints here?
*/
@@ -723,14 +867,14 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
CONSTRAINT_TYPE_TRANSLIKE))
{
/* TODO(sergey): Add used space check. */
- ComponentKey target_transform_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(target_transform_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ ComponentKey target_transform_key(&ct->tar->id,
+ DEG_NODE_TYPE_TRANSFORM);
+ add_relation(target_transform_key, constraint_op_key, cti->name);
}
-
}
-
- if (cti->flush_constraint_targets)
+ if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, 1);
+ }
}
}
}
@@ -742,13 +886,13 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
if (adt == NULL)
return;
- ComponentKey adt_key(id, DEPSNODE_TYPE_ANIMATION);
+ ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION);
/* animation */
if (adt->action || adt->nla_tracks.first) {
/* wire up dependency to time source */
TimeSourceKey time_src_key;
- add_relation(time_src_key, adt_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
+ add_relation(time_src_key, adt_key, "[TimeSrc -> Animation]");
// XXX: Hook up specific update callbacks for special properties which may need it...
@@ -758,9 +902,9 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
/* drivers */
LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) {
OperationKey driver_key(id,
- DEPSNODE_TYPE_PARAMETERS,
+ DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_DRIVER,
- fcu->rna_path,
+ fcu->rna_path ? fcu->rna_path : "",
fcu->array_index);
/* create the driver's relations to targets */
@@ -782,7 +926,8 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
FCurve *fcu_prev = NULL;
LINKLIST_FOREACH (FCurve *, fcu_candidate, &adt->drivers) {
/* Writing to different RNA paths is */
- if (!STREQ(fcu_candidate->rna_path, fcu->rna_path)) {
+ const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
+ if (!STREQ(fcu_candidate->rna_path, rna_path)) {
continue;
}
/* We only do relation from previous fcurve to previous one. */
@@ -798,26 +943,22 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
}
if (fcu_prev != NULL) {
OperationKey prev_driver_key(id,
- DEPSNODE_TYPE_PARAMETERS,
+ DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_DRIVER,
- fcu_prev->rna_path,
+ fcu_prev->rna_path ? fcu_prev->rna_path : "",
fcu_prev->array_index);
OperationKey driver_key(id,
- DEPSNODE_TYPE_PARAMETERS,
+ DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_DRIVER,
- fcu->rna_path,
+ fcu->rna_path ? fcu->rna_path : "",
fcu->array_index);
- add_relation(prev_driver_key,
- driver_key,
- DEPSREL_TYPE_OPERATION,
- "[Driver Order]");
+ add_relation(prev_driver_key, driver_key, "[Driver Order]");
}
}
/* prevent driver from occurring before own animation... */
if (adt->action || adt->nla_tracks.first) {
- add_relation(adt_key, driver_key, DEPSREL_TYPE_OPERATION,
- "[AnimData Before Drivers]");
+ add_relation(adt_key, driver_key, "[AnimData Before Drivers]");
}
}
}
@@ -826,26 +967,32 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
{
ChannelDriver *driver = fcu->driver;
OperationKey driver_key(id,
- DEPSNODE_TYPE_PARAMETERS,
+ DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_DRIVER,
- fcu->rna_path,
+ fcu->rna_path ? fcu->rna_path : "",
fcu->array_index);
bPoseChannel *pchan = NULL;
- /* create dependency between driver and data affected by it */
+ const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
+
+ /* Create dependency between driver and data affected by it. */
/* - direct property relationship... */
//RNAPathKey affected_key(id, fcu->rna_path);
- //add_relation(driver_key, affected_key, DEPSREL_TYPE_DRIVER, "[Driver -> Data] DepsRel");
+ //add_relation(driver_key, affected_key, "[Driver -> Data] DepsRel");
- /* driver -> data components (for interleaved evaluation - bones/constraints/modifiers) */
- // XXX: this probably should probably be moved out into a separate function
- if (strstr(fcu->rna_path, "pose.bones[") != NULL) {
+ /* Driver -> data components (for interleaved evaluation
+ * bones/constraints/modifiers).
+ */
+ // XXX: this probably should probably be moved out into a separate function.
+ if (strstr(rna_path, "pose.bones[") != NULL) {
/* interleaved drivers during bone eval */
- // TODO: ideally, if this is for a constraint, it goes to said constraint
+ /* TODO: ideally, if this is for a constraint, it goes to said
+ * constraint.
+ */
Object *ob = (Object *)id;
char *bone_name;
- bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
+ bone_name = BLI_str_quoted_substrN(rna_path, "pose.bones[");
pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
if (bone_name) {
@@ -854,109 +1001,122 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
}
if (pchan) {
- OperationKey bone_key(id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
- add_relation(driver_key, bone_key, DEPSREL_TYPE_DRIVER, "[Driver -> Bone]");
+ OperationKey bone_key(id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_LOCAL);
+ add_relation(driver_key, bone_key, "[Driver -> Bone]");
}
else {
fprintf(stderr,
"Couldn't find bone name for driver path - '%s'\n",
- fcu->rna_path);
+ rna_path);
}
}
- else if (GS(id->name) == ID_AR && strstr(fcu->rna_path, "bones[")) {
- /* drivers on armature-level bone settings (i.e. bbone stuff),
- * which will affect the evaluation of corresponding pose bones
+ else if (GS(id->name) == ID_AR && strstr(rna_path, "bones[")) {
+ /* Drivers on armature-level bone settings (i.e. bbone stuff),
+ * which will affect the evaluation of corresponding pose bones.
*/
IDDepsNode *arm_node = m_graph->find_id_node(id);
- char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
+ char *bone_name = BLI_str_quoted_substrN(rna_path, "bones[");
if (arm_node && bone_name) {
- /* find objects which use this, and make their eval callbacks depend on this */
+ /* Find objects which use this, and make their eval callbacks
+ * depend on this.
+ */
foreach (DepsRelation *rel, arm_node->outlinks) {
IDDepsNode *to_node = (IDDepsNode *)rel->to;
-
- /* we only care about objects with pose data which use this... */
+ /* We only care about objects with pose data which use this. */
if (GS(to_node->id->name) == ID_OB) {
Object *ob = (Object *)to_node->id;
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name); // NOTE: ob->pose may be NULL
-
- if (pchan) {
- OperationKey bone_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
- add_relation(driver_key, bone_key, DEPSREL_TYPE_DRIVER, "[Arm Bone -> Driver -> Bone]");
+ /* NOTE: ob->pose may be NULL. */
+ bPoseChannel *pchan = BKE_pose_channel_find_name(
+ ob->pose, bone_name);
+ if (pchan != NULL) {
+ OperationKey bone_key(&ob->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_LOCAL);
+ add_relation(driver_key,
+ bone_key,
+ "[Arm Bone -> Driver -> Bone]");
}
}
}
-
- /* free temp data */
+ /* Free temp data. */
MEM_freeN(bone_name);
bone_name = NULL;
}
else {
fprintf(stderr,
"Couldn't find armature bone name for driver path - '%s'\n",
- fcu->rna_path);
+ rna_path);
}
}
- else if (GS(id->name) == ID_OB && strstr(fcu->rna_path, "modifiers[")) {
- /* modifier driver - connect directly to the modifier */
- char *modifier_name = BLI_str_quoted_substrN(fcu->rna_path, "modifiers[");
- if (modifier_name) {
- OperationKey modifier_key(id,
- DEPSNODE_TYPE_GEOMETRY,
- DEG_OPCODE_GEOMETRY_MODIFIER,
- modifier_name);
- if (has_node(modifier_key)) {
- add_relation(driver_key, modifier_key, DEPSREL_TYPE_DRIVER, "[Driver -> Modifier]");
- }
- else {
- printf("Unexisting driver RNA path: %s\n", fcu->rna_path);
- }
-
- MEM_freeN(modifier_name);
+ else if (GS(id->name) == ID_OB && strstr(rna_path, "modifiers[")) {
+ OperationKey modifier_key(id,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+ if (has_node(modifier_key)) {
+ add_relation(driver_key, modifier_key, "[Driver -> Modifier]");
+ }
+ else {
+ printf("Unexisting driver RNA path: %s\n", rna_path);
}
}
- else if (GS(id->name) == ID_KE && strstr(fcu->rna_path, "key_blocks[")) {
- /* shape key driver - hook into the base geometry operation */
+ else if (GS(id->name) == ID_KE && strstr(rna_path, "key_blocks[")) {
+ /* Shape key driver - hook into the base geometry operation. */
// XXX: double check where this points
Key *shape_key = (Key *)id;
- ComponentKey geometry_key(shape_key->from, DEPSNODE_TYPE_GEOMETRY);
- add_relation(driver_key, geometry_key, DEPSREL_TYPE_DRIVER, "[Driver -> ShapeKey Geom]");
+ ComponentKey geometry_key(shape_key->from, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(driver_key, geometry_key, "[Driver -> ShapeKey Geom]");
}
- else if (strstr(fcu->rna_path, "key_blocks[")) {
- ComponentKey geometry_key(id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(driver_key, geometry_key, DEPSREL_TYPE_DRIVER, "[Driver -> ShapeKey Geom]");
+ else if (strstr(rna_path, "key_blocks[")) {
+ ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(driver_key, geometry_key, "[Driver -> ShapeKey Geom]");
}
else {
if (GS(id->name) == ID_OB) {
/* assume that driver affects a transform... */
- OperationKey local_transform_key(id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
- add_relation(driver_key, local_transform_key, DEPSREL_TYPE_OPERATION, "[Driver -> Transform]");
+ OperationKey local_transform_key(id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_LOCAL);
+ add_relation(driver_key,
+ local_transform_key,
+ "[Driver -> Transform]");
}
else if (GS(id->name) == ID_KE) {
- ComponentKey geometry_key(id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(driver_key, geometry_key, DEPSREL_TYPE_GEOMETRY_EVAL, "[Driver -> Shapekey Geometry]");
+ ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(driver_key,
+ geometry_key,
+ "[Driver -> Shapekey Geometry]");
}
}
-
- /* ensure that affected prop's update callbacks will be triggered once done */
- // TODO: implement this once the functionality to add these links exists in RNA
- // XXX: the data itself could also set this, if it were to be truly initialised later?
-
- /* loop over variables to get the target relationships */
+ /* Ensure that affected prop's update callbacks will be triggered once
+ * done.
+ */
+ /* TODO: Implement this once the functionality to add these links exists
+ * RNA.
+ */
+ /* XXX: the data itself could also set this, if it were to be truly
+ * initialised later?
+ */
+ /* Loop over variables to get the target relationships. */
LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) {
- /* only used targets */
+ /* Only used targets. */
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- if (dtar->id == NULL)
+ if (dtar->id == NULL) {
continue;
-
- /* special handling for directly-named bones */
+ }
+ /* Special handling for directly-named bones. */
if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) {
Object *ob = (Object *)dtar->id;
- bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+ bPoseChannel *target_pchan =
+ BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
if (target_pchan != NULL) {
- /* get node associated with bone */
+ /* Get node associated with bone. */
// XXX: watch the space!
/* Some cases can't use final bone transform, for example:
* - Driving the bone with itself (addressed here)
@@ -968,61 +1128,81 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
{
continue;
}
- OperationKey target_key(dtar->id, DEPSNODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[Bone Target -> Driver]");
+ OperationKey target_key(dtar->id,
+ DEG_NODE_TYPE_BONE,
+ target_pchan->name,
+ DEG_OPCODE_BONE_DONE);
+ add_relation(target_key,
+ driver_key,
+ "[Bone Target -> Driver]");
}
}
else if (dtar->flag & DTAR_FLAG_STRUCT_REF) {
- /* get node associated with the object's transforms */
- OperationKey target_key(dtar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
- add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[Target -> Driver]");
+ /* Get node associated with the object's transforms. */
+ if (dtar->id == id) {
+ /* Ignore input dependency if we're driving properties of
+ * the same ID, otherwise we'll be ending up in a cyclic
+ * dependency here.
+ */
+ continue;
+ }
+ OperationKey target_key(dtar->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, driver_key, "[Target -> Driver]");
}
else if (dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) {
- /* workaround for ensuring that local bone transforms don't end up
- * having to wait for pose eval to finish (to prevent cycles)
+ /* Workaround for ensuring that local bone transforms don't end
+ * up having to wait for pose eval to finish (to prevent cycles).
*/
Object *ob = (Object *)dtar->id;
- char *bone_name = BLI_str_quoted_substrN(dtar->rna_path, "pose.bones[");
- bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
- if (bone_name) {
+ char *bone_name = BLI_str_quoted_substrN(dtar->rna_path,
+ "pose.bones[");
+ bPoseChannel *target_pchan =
+ BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (bone_name != NULL) {
MEM_freeN(bone_name);
bone_name = NULL;
}
- if (target_pchan) {
+ if (target_pchan != NULL) {
if (dtar->id == id &&
pchan != NULL &&
STREQ(pchan->name, target_pchan->name))
{
continue;
}
- OperationKey bone_key(dtar->id, DEPSNODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_LOCAL);
- add_relation(bone_key, driver_key, DEPSREL_TYPE_DRIVER, "[RNA Bone -> Driver]");
+ OperationKey bone_key(dtar->id,
+ DEG_NODE_TYPE_BONE,
+ target_pchan->name,
+ DEG_OPCODE_BONE_LOCAL);
+ add_relation(bone_key, driver_key, "[RNA Bone -> Driver]");
}
}
else {
if (dtar->id == id) {
- /* Ignore input dependency if we're driving properties of the same ID,
- * otherwise we'll be ending up in a cyclic dependency here.
+ /* Ignore input dependency if we're driving properties of
+ * the same ID, otherwise we'll be ending up in a cyclic
+ * dependency here.
*/
continue;
}
- /* resolve path to get node */
- RNAPathKey target_key(dtar->id, dtar->rna_path ? dtar->rna_path : "");
- add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[RNA Target -> Driver]");
+ /* Resolve path to get node. */
+ RNAPathKey target_key(dtar->id,
+ dtar->rna_path ? dtar->rna_path : "");
+ add_relation(target_key, driver_key, "[RNA Target -> Driver]");
}
}
DRIVER_TARGETS_LOOPER_END
}
-
- /* It's quite tricky to detect if the driver actually depends on time or not,
- * so for now we'll be quite conservative here about optimization and consider
- * all python drivers to be depending on time.
+ /* It's quite tricky to detect if the driver actually depends on time or
+ * not, so for now we'll be quite conservative here about optimization and
+ * consider all python drivers to be depending on time.
*/
if ((driver->type == DRIVER_TYPE_PYTHON) &&
python_driver_depends_on_time(driver))
{
TimeSourceKey time_src_key;
- add_relation(time_src_key, driver_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Driver]");
+ add_relation(time_src_key, driver_key, "[TimeSrc -> Driver]");
}
}
@@ -1039,28 +1219,32 @@ void DepsgraphRelationBuilder::build_world(World *world)
/* TODO: other settings? */
/* textures */
- build_texture_stack(world_id, world->mtex);
+ build_texture_stack(world->mtex);
/* world's nodetree */
- build_nodetree(world_id, world->nodetree);
+ if (world->nodetree != NULL) {
+ build_nodetree(world->nodetree);
+ ComponentKey ntree_key(&world->nodetree->id, DEG_NODE_TYPE_PARAMETERS);
+ ComponentKey world_key(world_id, DEG_NODE_TYPE_PARAMETERS);
+ add_relation(ntree_key, world_key, "NTree->World Parameters");
+ }
}
void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
- OperationKey init_key(&scene->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_REBUILD);
- OperationKey sim_key(&scene->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_SIM);
+ OperationKey init_key(&scene->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_REBUILD);
+ OperationKey sim_key(&scene->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_SIM);
/* rel between the two sim-nodes */
- add_relation(init_key, sim_key, DEPSREL_TYPE_OPERATION, "Rigidbody [Init -> SimStep]");
+ add_relation(init_key, sim_key, "Rigidbody [Init -> SimStep]");
/* set up dependencies between these operations and other builtin nodes --------------- */
/* time dependency */
TimeSourceKey time_src_key;
- add_relation(time_src_key, init_key, DEPSREL_TYPE_TIME, "TimeSrc -> Rigidbody Reset/Rebuild (Optional)");
- add_relation(time_src_key, sim_key, DEPSREL_TYPE_TIME, "TimeSrc -> Rigidbody Sim Step");
+ add_relation(time_src_key, init_key, "TimeSrc -> Rigidbody Reset/Rebuild (Optional)");
/* objects - simulation participants */
if (rbw->group) {
@@ -1078,13 +1262,12 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
* XXX: there's probably a difference between passive and active
* - passive don't change, so may need to know full transform...
*/
- OperationKey rbo_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+ OperationKey rbo_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
eDepsOperation_Code trans_opcode = ob->parent ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL;
- OperationKey trans_op(&ob->id, DEPSNODE_TYPE_TRANSFORM, trans_opcode);
+ OperationKey trans_op(&ob->id, DEG_NODE_TYPE_TRANSFORM, trans_opcode);
- add_relation(trans_op, rbo_key, DEPSREL_TYPE_OPERATION, "Base Ob Transform -> RBO Sync");
- add_relation(sim_key, rbo_key, DEPSREL_TYPE_COMPONENT_ORDER, "Rigidbody Sim Eval -> RBO Sync");
+ add_relation(sim_key, rbo_key, "Rigidbody Sim Eval -> RBO Sync");
/* if constraints exist, those depend on the result of the rigidbody sim
* - This allows constraints to modify the result of the sim (i.e. clamping)
@@ -1095,22 +1278,25 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
* to control whether rigidbody eval gets interleaved into the constraint stack
*/
if (ob->constraints.first) {
- OperationKey constraint_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_CONSTRAINTS);
- add_relation(rbo_key, constraint_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Ob Constraints");
+ OperationKey constraint_key(&ob->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+ add_relation(rbo_key, constraint_key, "RBO Sync -> Ob Constraints");
}
else {
- /* final object transform depends on rigidbody */
- OperationKey done_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
- add_relation(rbo_key, done_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Done");
-
- // XXX: ubereval will be removed eventually, but we still need it in the meantime
- OperationKey uber_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL);
- add_relation(rbo_key, uber_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Uber (Temp)");
+ /* Final object transform depends on rigidbody.
+ *
+ * NOTE: Currently we consider final here an ubereval node.
+ * If it is gone we'll need to reconsider relation here.
+ */
+ OperationKey uber_key(&ob->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_OBJECT_UBEREVAL);
+ add_relation(rbo_key, uber_key, "RBO Sync -> Uber (Temp)");
}
-
- /* needed to get correct base values */
- add_relation(trans_op, sim_key, DEPSREL_TYPE_OPERATION, "Base Ob Transform -> Rigidbody Sim Eval");
+ /* Needed to get correct base values. */
+ add_relation(trans_op, sim_key, "Base Ob Transform -> Rigidbody Sim Eval");
}
}
@@ -1127,16 +1313,16 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
/* final result of the constraint object's transform controls how the
* constraint affects the physics sim for these objects
*/
- ComponentKey trans_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
- OperationKey ob1_key(&rbc->ob1->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
- OperationKey ob2_key(&rbc->ob2->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+ ComponentKey trans_key(&ob->id, DEG_NODE_TYPE_TRANSFORM);
+ OperationKey ob1_key(&rbc->ob1->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+ OperationKey ob2_key(&rbc->ob2->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
/* - constrained-objects sync depends on the constraint-holder */
- add_relation(trans_key, ob1_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint -> RBC.Object_1");
- add_relation(trans_key, ob2_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint -> RBC.Object_2");
+ add_relation(trans_key, ob1_key, "RigidBodyConstraint -> RBC.Object_1");
+ add_relation(trans_key, ob2_key, "RigidBodyConstraint -> RBC.Object_2");
/* - ensure that sim depends on this constraint's transform */
- add_relation(trans_key, sim_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint Transform -> RB Simulation");
+ add_relation(trans_key, sim_key, "RigidBodyConstraint Transform -> RB Simulation");
}
}
}
@@ -1145,8 +1331,15 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
{
TimeSourceKey time_src_key;
OperationKey obdata_ubereval_key(&ob->id,
- DEPSNODE_TYPE_GEOMETRY,
+ DEG_NODE_TYPE_GEOMETRY,
DEG_OPCODE_GEOMETRY_UBEREVAL);
+ OperationKey eval_init_key(&ob->id,
+ DEG_NODE_TYPE_EVAL_PARTICLES,
+ DEG_OPCODE_PSYS_EVAL_INIT);
+ /* TODO(sergey): Are all particle systems depends on time?
+ * Hair without dynamics i.e.
+ */
+ add_relation(time_src_key, eval_init_key, "TimeSrc -> PSys");
/* particle systems */
LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
@@ -1156,60 +1349,27 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
build_animdata(&part->id);
/* this particle system */
- OperationKey psys_key(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, psys->name);
+ OperationKey psys_key(&ob->id, DEG_NODE_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, G.is_rendering))
continue;
- /* TODO(sergey): Are all particle systems depends on time?
- * Hair without dynamics i.e.
- */
- add_relation(time_src_key, psys_key,
- DEPSREL_TYPE_TIME,
- "TimeSrc -> PSys");
+ add_relation(eval_init_key, psys_key, "Init -> PSys");
/* TODO(sergey): Currently particle update is just a placeholder,
* hook it to the ubereval node so particle system is getting updated
* on playback.
*/
- add_relation(psys_key,
- obdata_ubereval_key,
- DEPSREL_TYPE_OPERATION,
- "PSys -> UberEval");
-
-#if 0
- if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) {
- LINKLIST_FOREACH (ParticleTarget *, pt, &psys->targets) {
- if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) {
- node2 = dag_get_node(dag, pt->ob);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets");
- }
- }
- }
-
- if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
- node2 = dag_get_node(dag, part->dup_ob);
- /* note that this relation actually runs in the wrong direction, the problem
- * is that dupli system all have this (due to parenting), and the render
- * engine instancing assumes particular ordering of objects in list */
- dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualization");
- if (part->dup_ob->type == OB_MBALL)
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualization");
- }
-
- if (part->ren_as == PART_DRAW_GR && part->dup_group) {
- LINKLIST_FOREACH (GroupObject *, go, &part->dup_group->gobject) {
- node2 = dag_get_node(dag, go->ob);
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization");
- }
- }
-#endif
+ add_relation(psys_key, obdata_ubereval_key, "PSys -> UberEval");
/* collisions */
if (part->type != PART_HAIR) {
add_collision_relations(psys_key, scene, ob, part->collision_group, ob->lay, true, "Particle Collision");
}
+ else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd && psys->clmd->coll_parms) {
+ add_collision_relations(psys_key, scene, ob, psys->clmd->coll_parms->group, ob->lay | scene->lay, true, "Hair Collision");
+ }
/* effectors */
add_forcefield_relations(psys_key, scene, ob, psys, part->effector_weights, part->type == PART_HAIR, "Particle Field");
@@ -1225,19 +1385,16 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
ruleob = ((BoidRuleFollowLeader *)rule)->ob;
if (ruleob) {
- ComponentKey ruleob_key(&ruleob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(ruleob_key, psys_key, DEPSREL_TYPE_TRANSFORM, "Boid Rule");
+ ComponentKey ruleob_key(&ruleob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(ruleob_key, psys_key, "Boid Rule");
}
}
}
}
if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
- ComponentKey dup_ob_key(&part->dup_ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(dup_ob_key,
- psys_key,
- DEPSREL_TYPE_TRANSFORM,
- "Particle Object Visualization");
+ ComponentKey dup_ob_key(&part->dup_ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(dup_ob_key, psys_key, "Particle Object Visualization");
}
}
@@ -1247,20 +1404,32 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
* TODO(sergey): This relation should be altered once real granular update
* is implemented.
*/
- ComponentKey transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(transform_key,
- obdata_ubereval_key,
- DEPSREL_TYPE_GEOMETRY_EVAL,
- "Partcile Eval");
+ ComponentKey transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(transform_key, obdata_ubereval_key, "Partcile Eval");
/* pointcache */
// TODO...
}
+void DepsgraphRelationBuilder::build_cloth(Scene * /*scene*/,
+ Object *object,
+ ModifierData * /*md*/)
+{
+ OperationKey cache_key(&object->id,
+ DEG_NODE_TYPE_CACHE,
+ DEG_OPCODE_PLACEHOLDER,
+ "Cloth Modifier");
+ /* Cache component affects on modifier. */
+ OperationKey modifier_key(&object->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+ add_relation(cache_key, modifier_key, "Cloth Cache -> Cloth");
+}
+
/* Shapekeys */
void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
{
- ComponentKey obdata_key(obdata, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey obdata_key(obdata, DEG_NODE_TYPE_GEOMETRY);
/* attach animdata to geometry */
build_animdata(&key->id);
@@ -1268,8 +1437,8 @@ void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
if (key->adt) {
// TODO: this should really be handled in build_animdata, since many of these cases will need it
if (key->adt->action || key->adt->nla_tracks.first) {
- ComponentKey adt_key(&key->id, DEPSNODE_TYPE_ANIMATION);
- add_relation(adt_key, obdata_key, DEPSREL_TYPE_OPERATION, "Animation");
+ ComponentKey adt_key(&key->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(adt_key, obdata_key, "Animation");
}
/* NOTE: individual shapekey drivers are handled above already */
@@ -1277,8 +1446,8 @@ void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
/* attach to geometry */
// XXX: aren't shapekeys now done as a pseudo-modifier on object?
- //ComponentKey key_key(&key->id, DEPSNODE_TYPE_GEOMETRY); // FIXME: this doesn't exist
- //add_relation(key_key, obdata_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Shapekeys");
+ //ComponentKey key_key(&key->id, DEG_NODE_TYPE_GEOMETRY); // FIXME: this doesn't exist
+ //add_relation(key_key, obdata_key, "Shapekeys");
}
/**
@@ -1306,34 +1475,26 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
ID *obdata = (ID *)ob->data;
/* Init operation of object-level geometry evaluation. */
- OperationKey geom_init_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Init");
+ OperationKey geom_init_key(&ob->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Init");
/* get nodes for result of obdata's evaluation, and geometry evaluation on object */
- ComponentKey obdata_geom_key(obdata, DEPSNODE_TYPE_GEOMETRY);
- ComponentKey geom_key(&ob->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey obdata_geom_key(obdata, DEG_NODE_TYPE_GEOMETRY);
+ ComponentKey geom_key(&ob->id, DEG_NODE_TYPE_GEOMETRY);
/* link components to each other */
- add_relation(obdata_geom_key, geom_key, DEPSREL_TYPE_DATABLOCK, "Object Geometry Base Data");
+ add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data");
/* Modifiers */
- if (ob->modifiers.first) {
- OperationKey prev_mod_key;
+ if (ob->modifiers.first != NULL) {
+ OperationKey obdata_ubereval_key(&ob->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) {
const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
- OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
-
- if (md->prev) {
- /* Stack relation: modifier depends on previous modifier in the stack */
- add_relation(prev_mod_key, mod_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Modifier Stack");
- }
- else {
- /* Stack relation: first modifier depends on the geometry. */
- add_relation(geom_init_key, mod_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Modifier Stack");
- }
if (mti->updateDepsgraph) {
- DepsNodeHandle handle = create_node_handle(mod_key);
+ DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
mti->updateDepsgraph(
md,
bmain,
@@ -1344,7 +1505,7 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
if (BKE_object_modifier_use_time(ob, md)) {
TimeSourceKey time_src_key;
- add_relation(time_src_key, mod_key, DEPSREL_TYPE_TIME, "Time Source");
+ add_relation(time_src_key, obdata_ubereval_key, "Time Source");
/* Hacky fix for T45633 (Animated modifiers aren't updated)
*
@@ -1353,24 +1514,24 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
*/
/* XXX: Remove this hack when these links are added as part of build_animdata() instead */
if (modifier_dependsOnTime(md) == false && needs_animdata_node(&ob->id)) {
- ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
- add_relation(animation_key, mod_key, DEPSREL_TYPE_OPERATION, "Modifier Animation");
+ ComponentKey animation_key(&ob->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(animation_key, obdata_ubereval_key, "Modifier Animation");
}
}
- prev_mod_key = mod_key;
+ if (md->type == eModifierType_Cloth) {
+ build_cloth(scene, ob, md);
+ }
}
}
/* materials */
if (ob->totcol) {
- int a;
-
- for (a = 1; a <= ob->totcol; a++) {
+ for (int a = 1; a <= ob->totcol; a++) {
Material *ma = give_current_material(ob, a);
-
- if (ma)
- build_material(&ob->id, ma);
+ if (ma != NULL) {
+ build_material(ma);
+ }
}
}
@@ -1385,15 +1546,8 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
*/
if (ob->type != OB_ARMATURE) {
/* Armatures does no longer require uber node. */
- OperationKey obdata_ubereval_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL);
- if (ob->modifiers.last) {
- ModifierData *md = (ModifierData *)ob->modifiers.last;
- OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
- add_relation(mod_key, obdata_ubereval_key, DEPSREL_TYPE_OPERATION, "Object Geometry UberEval");
- }
- else {
- add_relation(geom_init_key, obdata_ubereval_key, DEPSREL_TYPE_OPERATION, "Object Geometry UberEval");
- }
+ OperationKey obdata_ubereval_key(&ob->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL);
+ add_relation(geom_init_key, obdata_ubereval_key, "Object Geometry UberEval");
}
if (obdata->tag & LIB_TAG_DOIT) {
@@ -1402,13 +1556,26 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
obdata->tag |= LIB_TAG_DOIT;
/* Link object data evaluation node to exit operation. */
- OperationKey obdata_geom_eval_key(obdata, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
- OperationKey obdata_geom_done_key(obdata, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Done");
- add_relation(obdata_geom_eval_key, obdata_geom_done_key, DEPSREL_TYPE_DATABLOCK, "ObData Geom Eval Done");
+ OperationKey obdata_geom_eval_key(obdata, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ OperationKey obdata_geom_done_key(obdata, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Done");
+ add_relation(obdata_geom_eval_key, obdata_geom_done_key, "ObData Geom Eval Done");
/* type-specific node/links */
switch (ob->type) {
case OB_MESH:
+ /* NOTE: This is compatibility code to support particle systems
+ *
+ * for viewport being properly rendered in final render mode.
+ * This relation is similar to what dag_object_time_update_flags()
+ * was doing for mesh objects with particle system/
+ *
+ * Ideally we need to get rid of this relation.
+ */
+ if (ob->particlesystem.first != NULL) {
+ TimeSourceKey time_key;
+ OperationKey obdata_ubereval_key(&ob->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL);
+ add_relation(time_key, obdata_ubereval_key, "Legacy particle time");
+ }
break;
case OB_MBALL:
@@ -1418,10 +1585,10 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
/* motherball - mom depends on children! */
if (mom != ob) {
/* non-motherball -> cannot be directly evaluated! */
- ComponentKey mom_key(&mom->id, DEPSNODE_TYPE_GEOMETRY);
- ComponentKey transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(geom_key, mom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Metaball Motherball");
- add_relation(transform_key, mom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Metaball Motherball");
+ ComponentKey mom_key(&mom->id, DEG_NODE_TYPE_GEOMETRY);
+ ComponentKey transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(geom_key, mom_key, "Metaball Motherball");
+ add_relation(transform_key, mom_key, "Metaball Motherball");
}
break;
}
@@ -1434,20 +1601,20 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
/* curve's dependencies */
// XXX: these needs geom data, but where is geom stored?
if (cu->bevobj) {
- ComponentKey bevob_key(&cu->bevobj->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey bevob_key(&cu->bevobj->id, DEG_NODE_TYPE_GEOMETRY);
build_object(bmain, scene, cu->bevobj);
- add_relation(bevob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Bevel");
+ add_relation(bevob_key, geom_key, "Curve Bevel");
}
if (cu->taperobj) {
- ComponentKey taperob_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey taperob_key(&cu->taperobj->id, DEG_NODE_TYPE_GEOMETRY);
build_object(bmain, scene, cu->taperobj);
- add_relation(taperob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Taper");
+ add_relation(taperob_key, geom_key, "Curve Taper");
}
if (ob->type == OB_FONT) {
if (cu->textoncurve) {
- ComponentKey textoncurve_key(&cu->textoncurve->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey textoncurve_key(&cu->textoncurve->id, DEG_NODE_TYPE_GEOMETRY);
build_object(bmain, scene, cu->textoncurve);
- add_relation(textoncurve_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Text on Curve");
+ add_relation(textoncurve_key, geom_key, "Text on Curve");
}
}
break;
@@ -1471,14 +1638,13 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
}
if (needs_animdata_node(obdata)) {
- ComponentKey animation_key(obdata, DEPSNODE_TYPE_ANIMATION);
- ComponentKey parameters_key(obdata, DEPSNODE_TYPE_PARAMETERS);
- add_relation(animation_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "Geom Parameters");
+ ComponentKey animation_key(obdata, DEG_NODE_TYPE_ANIMATION);
+ ComponentKey parameters_key(obdata, DEG_NODE_TYPE_PARAMETERS);
+ add_relation(animation_key, parameters_key, "Geom Parameters");
/* Evaluation usually depends on animation.
* TODO(sergey): Need to re-hook it after granular update is implemented..
*/
- add_relation(animation_key, obdata_geom_eval_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Animation");
+ add_relation(animation_key, obdata_geom_eval_key, "Animation");
}
}
@@ -1493,19 +1659,18 @@ void DepsgraphRelationBuilder::build_camera(Object *ob)
}
camera_id->tag |= LIB_TAG_DOIT;
- ComponentKey parameters_key(camera_id, DEPSNODE_TYPE_PARAMETERS);
+ ComponentKey parameters_key(camera_id, DEG_NODE_TYPE_PARAMETERS);
if (needs_animdata_node(camera_id)) {
- ComponentKey animation_key(camera_id, DEPSNODE_TYPE_ANIMATION);
- add_relation(animation_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "Camera Parameters");
+ ComponentKey animation_key(camera_id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key, "Camera Parameters");
}
/* DOF */
if (cam->dof_ob) {
- ComponentKey ob_param_key(&ob->id, DEPSNODE_TYPE_PARAMETERS);
- ComponentKey dof_ob_key(&cam->dof_ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(dof_ob_key, ob_param_key, DEPSREL_TYPE_TRANSFORM, "Camera DOF");
+ ComponentKey ob_param_key(&ob->id, DEG_NODE_TYPE_PARAMETERS);
+ ComponentKey dof_ob_key(&cam->dof_ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(dof_ob_key, ob_param_key, "Camera DOF");
}
}
@@ -1519,27 +1684,25 @@ void DepsgraphRelationBuilder::build_lamp(Object *ob)
}
lamp_id->tag |= LIB_TAG_DOIT;
- ComponentKey parameters_key(lamp_id, DEPSNODE_TYPE_PARAMETERS);
+ ComponentKey parameters_key(lamp_id, DEG_NODE_TYPE_PARAMETERS);
if (needs_animdata_node(lamp_id)) {
- ComponentKey animation_key(lamp_id, DEPSNODE_TYPE_ANIMATION);
- add_relation(animation_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "Lamp Parameters");
+ ComponentKey animation_key(lamp_id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key, "Lamp Parameters");
}
/* lamp's nodetree */
if (la->nodetree) {
- build_nodetree(lamp_id, la->nodetree);
- ComponentKey nodetree_key(&la->nodetree->id, DEPSNODE_TYPE_PARAMETERS);
- add_relation(nodetree_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "NTree->Lamp Parameters");
+ build_nodetree(la->nodetree);
+ ComponentKey nodetree_key(&la->nodetree->id, DEG_NODE_TYPE_PARAMETERS);
+ add_relation(nodetree_key, parameters_key, "NTree->Lamp Parameters");
}
/* textures */
- build_texture_stack(lamp_id, la->mtex);
+ build_texture_stack(la->mtex);
}
-void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
+void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
{
if (!ntree)
return;
@@ -1549,7 +1712,7 @@ void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
build_animdata(ntree_id);
OperationKey parameters_key(ntree_id,
- DEPSNODE_TYPE_PARAMETERS,
+ DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_PLACEHOLDER,
"Parameters Eval");
@@ -1557,38 +1720,34 @@ void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
if (bnode->id) {
if (GS(bnode->id->name) == ID_MA) {
- build_material(owner, (Material *)bnode->id);
+ build_material((Material *)bnode->id);
}
else if (bnode->type == ID_TE) {
- build_texture(owner, (Tex *)bnode->id);
+ build_texture((Tex *)bnode->id);
}
else if (bnode->type == NODE_GROUP) {
bNodeTree *group_ntree = (bNodeTree *)bnode->id;
if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
- build_nodetree(owner, group_ntree);
+ build_nodetree(group_ntree);
group_ntree->id.tag |= LIB_TAG_DOIT;
}
OperationKey group_parameters_key(&group_ntree->id,
- DEPSNODE_TYPE_PARAMETERS,
+ DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_PLACEHOLDER,
"Parameters Eval");
- add_relation(group_parameters_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "Group Node");
+ add_relation(group_parameters_key, parameters_key, "Group Node");
}
}
}
if (needs_animdata_node(ntree_id)) {
- ComponentKey animation_key(ntree_id, DEPSNODE_TYPE_ANIMATION);
- add_relation(animation_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "NTree Parameters");
+ ComponentKey animation_key(ntree_id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key, "NTree Parameters");
}
-
- // TODO: link from nodetree to owner_component?
}
/* Recursively build graph for material */
-void DepsgraphRelationBuilder::build_material(ID *owner, Material *ma)
+void DepsgraphRelationBuilder::build_material(Material *ma)
{
ID *ma_id = &ma->id;
if (ma_id->tag & LIB_TAG_DOIT) {
@@ -1600,14 +1759,25 @@ void DepsgraphRelationBuilder::build_material(ID *owner, Material *ma)
build_animdata(ma_id);
/* textures */
- build_texture_stack(owner, ma->mtex);
+ build_texture_stack(ma->mtex);
/* material's nodetree */
- build_nodetree(owner, ma->nodetree);
+ if (ma->nodetree != NULL) {
+ build_nodetree(ma->nodetree);
+ OperationKey ntree_key(&ma->nodetree->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "Parameters Eval");
+ OperationKey material_key(&ma->id,
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_PLACEHOLDER,
+ "Material Update");
+ add_relation(ntree_key, material_key, "Material's NTree");
+ }
}
/* Recursively build graph for texture */
-void DepsgraphRelationBuilder::build_texture(ID *owner, Tex *tex)
+void DepsgraphRelationBuilder::build_texture(Tex *tex)
{
ID *tex_id = &tex->id;
if (tex_id->tag & LIB_TAG_DOIT) {
@@ -1619,11 +1789,11 @@ void DepsgraphRelationBuilder::build_texture(ID *owner, Tex *tex)
build_animdata(tex_id);
/* texture's nodetree */
- build_nodetree(owner, tex->nodetree);
+ build_nodetree(tex->nodetree);
}
/* Texture-stack attached to some shading datablock */
-void DepsgraphRelationBuilder::build_texture_stack(ID *owner, MTex **texture_stack)
+void DepsgraphRelationBuilder::build_texture_stack(MTex **texture_stack)
{
int i;
@@ -1631,17 +1801,17 @@ void DepsgraphRelationBuilder::build_texture_stack(ID *owner, MTex **texture_sta
for (i = 0; i < MAX_MTEX; i++) {
MTex *mtex = texture_stack[i];
if (mtex && mtex->tex)
- build_texture(owner, mtex->tex);
+ build_texture(mtex->tex);
}
}
void DepsgraphRelationBuilder::build_compositor(Scene *scene)
{
/* For now, just a plain wrapper? */
- build_nodetree(&scene->id, scene->nodetree);
+ build_nodetree(scene->nodetree);
}
-void DepsgraphRelationBuilder::build_gpencil(ID *UNUSED(owner), bGPdata *gpd)
+void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd)
{
/* animation */
build_animdata(&gpd->id);
@@ -1665,8 +1835,18 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) {
void DepsgraphRelationBuilder::build_mask(Mask *mask)
{
- /* Animation. */
- build_animdata(&mask->id);
+ ID *mask_id = &mask->id;
+ /* F-Curve animation. */
+ build_animdata(mask_id);
+ /* Own mask animation. */
+ OperationKey mask_animation_key(mask_id,
+ DEG_NODE_TYPE_ANIMATION,
+ DEG_OPCODE_MASK_ANIMATION);
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, mask_animation_key, "TimeSrc -> Mask Animation");
+ /* Final mask evaluation. */
+ ComponentKey parameters_key(mask_id, DEG_NODE_TYPE_PARAMETERS);
+ add_relation(mask_animation_key, parameters_key, "Mask Animation -> Mask Eval");
}
void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 6e8485bee30..02f8fc69070 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -58,6 +58,7 @@ struct Main;
struct Mask;
struct Material;
struct MTex;
+struct ModifierData;
struct MovieClip;
struct bNodeTree;
struct Object;
@@ -77,17 +78,12 @@ struct Depsgraph;
struct DepsNode;
struct DepsNodeHandle;
struct RootDepsNode;
-struct SubgraphDepsNode;
struct IDDepsNode;
struct TimeSourceDepsNode;
struct ComponentDepsNode;
struct OperationDepsNode;
struct RootPChanMap;
-struct RootKey {
- RootKey();
-};
-
struct TimeSourceKey
{
TimeSourceKey();
@@ -171,22 +167,21 @@ struct DepsgraphRelationBuilder
{
DepsgraphRelationBuilder(Depsgraph *graph);
+ void begin_build(Main *bmain);
+
template <typename KeyFrom, typename KeyTo>
void add_relation(const KeyFrom& key_from,
const KeyTo& key_to,
- eDepsRelation_Type type,
const char *description);
template <typename KeyTo>
void add_relation(const TimeSourceKey& key_from,
const KeyTo& key_to,
- eDepsRelation_Type type,
const char *description);
template <typename KeyType>
void add_node_handle_relation(const KeyType& key_from,
const DepsNodeHandle *handle,
- eDepsRelation_Type type,
const char *description);
void build_scene(Main *bmain, Scene *scene);
@@ -203,6 +198,7 @@ struct DepsgraphRelationBuilder
void build_world(World *world);
void build_rigidbody(Scene *scene);
void build_particles(Scene *scene, Object *ob);
+ void build_cloth(Scene *scene, Object *object, ModifierData *md);
void build_ik_pose(Object *ob,
bPoseChannel *pchan,
bConstraint *con,
@@ -217,12 +213,12 @@ struct DepsgraphRelationBuilder
void build_obdata_geom(Main *bmain, Scene *scene, Object *ob);
void build_camera(Object *ob);
void build_lamp(Object *ob);
- void build_nodetree(ID *owner, bNodeTree *ntree);
- void build_material(ID *owner, Material *ma);
- void build_texture(ID *owner, Tex *tex);
- void build_texture_stack(ID *owner, MTex **texture_stack);
+ void build_nodetree(bNodeTree *ntree);
+ void build_material(Material *ma);
+ void build_texture(Tex *tex);
+ void build_texture_stack(MTex **texture_stack);
void build_compositor(Scene *scene);
- void build_gpencil(ID *owner, bGPdata *gpd);
+ void build_gpencil(bGPdata *gpd);
void build_cachefile(CacheFile *cache_file);
void build_mask(Mask *mask);
void build_movieclip(MovieClip *clip);
@@ -233,8 +229,9 @@ struct DepsgraphRelationBuilder
template <typename KeyType>
OperationDepsNode *find_operation_node(const KeyType &key);
+ Depsgraph *getGraph();
+
protected:
- RootDepsNode *find_node(const RootKey &key) const;
TimeSourceDepsNode *find_node(const TimeSourceKey &key) const;
ComponentDepsNode *find_node(const ComponentKey &key) const;
OperationDepsNode *find_node(const OperationKey &key) const;
@@ -246,7 +243,6 @@ protected:
const char *description);
void add_operation_relation(OperationDepsNode *node_from,
OperationDepsNode *node_to,
- eDepsRelation_Type type,
const char *description);
template <typename KeyType>
@@ -286,7 +282,6 @@ OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType&
template <typename KeyFrom, typename KeyTo>
void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
const KeyTo &key_to,
- eDepsRelation_Type type,
const char *description)
{
DepsNode *node_from = find_node(key_from);
@@ -294,27 +289,27 @@ void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
if (op_from && op_to) {
- add_operation_relation(op_from, op_to, type, description);
+ add_operation_relation(op_from, op_to, description);
}
else {
if (!op_from) {
/* XXX TODO handle as error or report if needed */
node_from = find_node(key_from);
- fprintf(stderr, "add_relation(%d, %s) - Could not find op_from (%s)\n",
- type, description, key_from.identifier().c_str());
+ fprintf(stderr, "add_relation(%s) - Could not find op_from (%s)\n",
+ description, key_from.identifier().c_str());
}
else {
- fprintf(stderr, "add_relation(%d, %s) - Failed, but op_from (%s) was ok\n",
- type, description, key_from.identifier().c_str());
+ fprintf(stderr, "add_relation(%s) - Failed, but op_from (%s) was ok\n",
+ description, key_from.identifier().c_str());
}
if (!op_to) {
/* XXX TODO handle as error or report if needed */
- fprintf(stderr, "add_relation(%d, %s) - Could not find op_to (%s)\n",
- type, description, key_to.identifier().c_str());
+ fprintf(stderr, "add_relation(%s) - Could not find op_to (%s)\n",
+ description, key_to.identifier().c_str());
}
else {
- fprintf(stderr, "add_relation(%d, %s) - Failed, but op_to (%s) was ok\n",
- type, description, key_to.identifier().c_str());
+ fprintf(stderr, "add_relation(%s) - Failed, but op_to (%s) was ok\n",
+ description, key_to.identifier().c_str());
}
}
}
@@ -322,11 +317,8 @@ void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
template <typename KeyTo>
void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
const KeyTo &key_to,
- eDepsRelation_Type type,
const char *description)
{
- (void)type; /* Ignored in release builds. */
- BLI_assert(type == DEPSREL_TYPE_TIME);
TimeSourceDepsNode *time_from = find_node(key_from);
DepsNode *node_to = find_node(key_to);
OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
@@ -341,23 +333,22 @@ template <typename KeyType>
void DepsgraphRelationBuilder::add_node_handle_relation(
const KeyType &key_from,
const DepsNodeHandle *handle,
- eDepsRelation_Type type,
const char *description)
{
DepsNode *node_from = find_node(key_from);
OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
OperationDepsNode *op_to = handle->node->get_entry_operation();
if (op_from && op_to) {
- add_operation_relation(op_from, op_to, type, description);
+ add_operation_relation(op_from, op_to, description);
}
else {
if (!op_from) {
- fprintf(stderr, "add_node_handle_relation(%d, %s) - Could not find op_from (%s)\n",
- type, description, key_from.identifier().c_str());
+ fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_from (%s)\n",
+ description, key_from.identifier().c_str());
}
if (!op_to) {
- fprintf(stderr, "add_node_handle_relation(%d, %s) - Could not find op_to (%s)\n",
- type, description, key_from.identifier().c_str());
+ fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_to (%s)\n",
+ description, key_from.identifier().c_str());
}
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
index feae8bca303..9d6ab3358a7 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
@@ -35,13 +35,6 @@
namespace DEG {
/////////////////////////////////////////
-// Root.
-
-RootKey::RootKey()
-{
-}
-
-/////////////////////////////////////////
// Time source.
TimeSourceKey::TimeSourceKey()
@@ -64,7 +57,7 @@ string TimeSourceKey::identifier() const
ComponentKey::ComponentKey()
: id(NULL),
- type(DEPSNODE_TYPE_UNDEFINED),
+ type(DEG_NODE_TYPE_UNDEFINED),
name("")
{
}
@@ -90,7 +83,7 @@ string ComponentKey::identifier() const
OperationKey::OperationKey()
: id(NULL),
- component_type(DEPSNODE_TYPE_UNDEFINED),
+ component_type(DEG_NODE_TYPE_UNDEFINED),
component_name(""),
opcode(DEG_OPCODE_OPERATION),
name(""),
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index 2b4c000f483..ca548ed33d0 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -38,10 +38,10 @@
#include "MEM_guardedalloc.h"
-extern "C" {
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_blenlib.h"
+extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -51,10 +51,10 @@ extern "C" {
#include "BKE_action.h"
#include "BKE_armature.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-} /* extern "C" */
#include "intern/builder/deg_builder.h"
#include "intern/builder/deg_builder_pchanmap.h"
@@ -83,7 +83,15 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
* - see notes on direction of rel below...
*/
bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
- OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER);
+ OperationKey pchan_local_key(&ob->id, DEG_NODE_TYPE_BONE,
+ pchan->name, DEG_OPCODE_BONE_LOCAL);
+ OperationKey init_ik_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK);
+ OperationKey solver_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE,
+ rootchan->name,
+ DEG_OPCODE_POSE_IK_SOLVER);
+
+ add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree");
+ add_relation(init_ik_key, solver_key, "Init IK -> IK Solver");
/* IK target */
// XXX: this should get handled as part of the constraint code
@@ -96,25 +104,25 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
* testing IK solver.
*/
// FIXME: geometry targets...
- ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+ ComponentKey pose_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE);
if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
/* TODO(sergey): This is only for until granular update stores intermediate result. */
if (data->tar != ob) {
/* different armature - can just read the results */
- ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget);
- add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ ComponentKey target_key(&data->tar->id, DEG_NODE_TYPE_BONE, data->subtarget);
+ add_relation(target_key, pose_key, con->name);
}
else {
/* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */
- OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE);
- add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ OperationKey target_key(&data->tar->id, DEG_NODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE);
+ add_relation(target_key, solver_key, con->name);
}
}
else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
/* vertex group target */
/* NOTE: for now, we don't need to represent vertex groups separately... */
- ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
+ ComponentKey target_key(&data->tar->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(target_key, solver_key, con->name);
if (data->tar->type == OB_MESH) {
OperationDepsNode *node2 = find_operation_node(target_key);
@@ -125,8 +133,8 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
}
else {
/* Standard Object Target */
- ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ ComponentKey target_key(&data->tar->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(target_key, pose_key, con->name);
}
if ((data->tar == ob) && (data->subtarget[0])) {
@@ -142,14 +150,14 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
if (data->poletar != NULL) {
if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
// XXX: same armature issues - ready vs done?
- ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget);
- add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ ComponentKey target_key(&data->poletar->id, DEG_NODE_TYPE_BONE, data->polesubtarget);
+ add_relation(target_key, solver_key, con->name);
}
else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) {
/* vertex group target */
/* NOTE: for now, we don't need to represent vertex groups separately... */
- ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
+ ComponentKey target_key(&data->poletar->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(target_key, solver_key, con->name);
if (data->poletar->type == OB_MESH) {
OperationDepsNode *node2 = find_operation_node(target_key);
@@ -159,8 +167,8 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
}
}
else {
- ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ ComponentKey target_key(&data->poletar->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(target_key, solver_key, con->name);
}
}
@@ -170,19 +178,17 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
bPoseChannel *parchan = pchan;
/* exclude tip from chain? */
if (!(data->flag & CONSTRAINT_IK_TIP)) {
- OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
+ OperationKey tip_transforms_key(&ob->id, DEG_NODE_TYPE_BONE,
parchan->name, DEG_OPCODE_BONE_LOCAL);
- add_relation(solver_key, tip_transforms_key,
- DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
+ add_relation(solver_key, tip_transforms_key, "IK Solver Result");
parchan = pchan->parent;
}
root_map->add_bone(parchan->name, rootchan->name);
- OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
+ OperationKey parchan_transforms_key(&ob->id, DEG_NODE_TYPE_BONE,
parchan->name, DEG_OPCODE_BONE_READY);
- add_relation(parchan_transforms_key, solver_key,
- DEPSREL_TYPE_TRANSFORM, "IK Solver Owner");
+ add_relation(parchan_transforms_key, solver_key, "IK Solver Owner");
/* Walk to the chain's root */
//size_t segcount = 0;
@@ -196,15 +202,15 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
* grab the result with IK solver results...
*/
if (parchan != pchan) {
- OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
- add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent");
+ OperationKey parent_key(&ob->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+ add_relation(parent_key, solver_key, "IK Chain Parent");
- 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");
+ OperationKey done_key(&ob->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, done_key, "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");
+ OperationKey final_transforms_key(&ob->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, "IK Solver Result");
}
parchan->flag |= POSE_DONE;
@@ -219,8 +225,8 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
parchan = parchan->parent;
}
- OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
- add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+ OperationKey flush_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ add_relation(solver_key, flush_key, "PoseEval Result-Bone Link");
}
/* Spline IK Eval Steps */
@@ -231,14 +237,14 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
{
bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
- OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
- OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
+ OperationKey transforms_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey solver_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
/* attach owner to IK Solver too
* - assume that owner is always part of chain
* - see notes on direction of rel below...
*/
- add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner");
+ add_relation(transforms_key, solver_key, "Spline IK Solver Owner");
/* attach path dependency to solver */
if (data->tar) {
@@ -247,14 +253,14 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
* See IK pose for a bit more information.
*/
// TODO: the bigggest point here is that we need the curve PATH and not just the general geometry...
- ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
- ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
- add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel");
+ ComponentKey target_key(&data->tar->id, DEG_NODE_TYPE_GEOMETRY);
+ ComponentKey pose_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE);
+ add_relation(target_key, pose_key, "[Curve.Path -> Spline IK] DepsRel");
}
pchan->flag |= POSE_DONE;
- OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result");
+ OperationKey final_transforms_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, "Spline IK Result");
root_map->add_bone(pchan->name, rootchan->name);
@@ -270,16 +276,16 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
* grab the result with IK solver results...
*/
if (parchan != pchan) {
- OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
- add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update");
+ OperationKey parent_key(&ob->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+ add_relation(parent_key, solver_key, "Spline IK Solver Update");
- 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");
+ OperationKey done_key(&ob->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, done_key, "IK Chain 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, "Spline IK Solver Result");
+ OperationKey final_transforms_key(&ob->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, "Spline IK Solver Result");
root_map->add_bone(parchan->name, rootchan->name);
@@ -288,8 +294,8 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */
}
- OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
- add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+ OperationKey flush_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ add_relation(solver_key, flush_key, "PoseEval Result-Bone Link");
}
/* Pose/Armature Bones Graph */
@@ -301,21 +307,23 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
// TODO: selection status?
/* attach links between pose operations */
- OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
- OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ OperationKey init_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
+ OperationKey init_ik_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK);
+ OperationKey flush_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
- add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]");
+ add_relation(init_key, init_ik_key, "Pose Init -> Pose Init IK");
+ add_relation(init_ik_key, flush_key, "Pose Init IK -> Pose Cleanup");
/* Make sure pose is up-to-date with armature updates. */
OperationKey armature_key(&arm->id,
- DEPSNODE_TYPE_PARAMETERS,
+ DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_PLACEHOLDER,
"Armature Eval");
- add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency");
+ add_relation(armature_key, init_key, "Data dependency");
if (needs_animdata_node(&ob->id)) {
- ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
- add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
+ ComponentKey animation_key(&ob->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(animation_key, init_key, "Rig Animation");
}
/* IK Solvers...
@@ -370,26 +378,25 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
/* TODO(sergey): Once partial updates are possible use relation between
* object transform and solver itself in it's build function.
*/
- ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
- ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms");
+ ComponentKey pose_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE);
+ ComponentKey local_transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(local_transform_key, pose_key, "Local Transforms");
}
-
/* links between operations for each bone */
LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
- OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
- OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
- OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
- OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+ OperationKey bone_local_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ OperationKey bone_pose_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
+ OperationKey bone_ready_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey bone_done_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
pchan->flag &= ~POSE_DONE;
/* pose init to bone local */
- add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link");
+ add_relation(init_key, bone_local_key, "PoseEval Source-Bone Link");
/* local to pose parenting operation */
- add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link");
+ add_relation(bone_local_key, bone_pose_key, "Bone Local - PoseSpace Link");
/* parent relation */
if (pchan->parent != NULL) {
@@ -403,26 +410,26 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
parent_key_opcode = DEG_OPCODE_BONE_DONE;
}
- OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
- add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]");
+ OperationKey parent_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
+ add_relation(parent_key, bone_pose_key, "[Parent Bone -> Child Bone]");
}
/* constraints */
if (pchan->constraints.first != NULL) {
/* constraints stack and constraint dependencies */
- build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
+ build_constraints(scene, &ob->id, DEG_NODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
/* pose -> constraints */
- OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS);
- add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack");
+ OperationKey constraints_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS);
+ add_relation(bone_pose_key, constraints_key, "Constraints Stack");
/* constraints -> ready */
// TODO: when constraint stack is exploded, this step should occur before the first IK solver
- add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready");
+ add_relation(constraints_key, bone_ready_key, "Constraints -> Ready");
}
else {
/* pose -> ready */
- add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready");
+ add_relation(bone_pose_key, bone_ready_key, "Pose -> Ready");
}
/* bone ready -> done
@@ -430,25 +437,25 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
* For IK chains however, an additional rel is created from IK to done,
* with transitive reduction removing this one...
*/
- add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
+ add_relation(bone_ready_key, bone_done_key, "Ready -> Done");
/* assume that all bones must be done for the pose to be ready (for deformers) */
- add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+ add_relation(bone_done_key, flush_key, "PoseEval Result-Bone Link");
}
}
void DepsgraphRelationBuilder::build_proxy_rig(Object *ob)
{
- OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
- OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ OperationKey pose_init_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
+ OperationKey pose_done_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
- OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
- OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
- OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local");
- add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready");
- add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
- add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done");
+ OperationKey bone_local_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ OperationKey bone_ready_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey bone_done_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(pose_init_key, bone_local_key, "Pose Init -> Bone Local");
+ add_relation(bone_local_key, bone_ready_key, "Local -> Ready");
+ add_relation(bone_ready_key, bone_done_key, "Ready -> Done");
+ add_relation(bone_done_key, pose_done_key, "Bone Done -> Pose Done");
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
index 6b51a957da0..6a9568e7e8d 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
@@ -38,20 +38,20 @@
#include "MEM_guardedalloc.h"
-extern "C" {
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_blenlib.h"
+extern "C" {
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BKE_main.h"
#include "BKE_node.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-} /* extern "C" */
#include "intern/builder/deg_builder.h"
#include "intern/builder/deg_builder_pchanmap.h"
@@ -69,45 +69,14 @@ namespace DEG {
void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
{
- /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
- * created or not.
- */
- BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- /* XXX nested node trees are not included in tag-clearing above,
- * so we need to do this manually.
- */
- FOREACH_NODETREE(bmain, nodetree, id) {
- if (id != (ID *)nodetree)
- nodetree->id.tag &= ~LIB_TAG_DOIT;
- } FOREACH_NODETREE_END
-
if (scene->set) {
- // TODO: link set to scene, especially our timesource...
+ build_scene(bmain, scene->set);
}
/* scene objects */
LINKLIST_FOREACH (Base *, base, &scene->base) {
Object *ob = base->object;
-
- /* object itself */
build_object(bmain, scene, ob);
-
- /* object that this is a proxy for */
- if (ob->proxy) {
- ob->proxy->proxy_from = ob;
- build_object(bmain, scene, ob->proxy);
- /* TODO(sergey): This is an inverted relation, matches old depsgraph
- * behavior and need to be investigated if it still need to be inverted.
- */
- ComponentKey ob_pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
- ComponentKey proxy_pose_key(&ob->proxy->id, DEPSNODE_TYPE_EVAL_POSE);
- add_relation(ob_pose_key, proxy_pose_key, DEPSREL_TYPE_TRANSFORM, "Proxy");
- }
-
- /* Object dupligroup. */
- if (ob->dup_group) {
- build_group(bmain, scene, ob, ob->dup_group);
- }
}
/* rigidbody */
@@ -132,7 +101,7 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
/* grease pencil */
if (scene->gpd) {
- build_gpencil(&scene->id, scene->gpd);
+ build_gpencil(scene->gpd);
}
/* Masks. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index da71db09f3d..b12af21fc8d 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -30,9 +30,7 @@
#include "intern/builder/deg_builder_transitive.h"
-extern "C" {
#include "MEM_guardedalloc.h"
-}
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
@@ -105,7 +103,7 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
/* Increment in advance, so we can safely remove the relation. */
++it_rel;
- if (rel->from->type == DEPSNODE_TYPE_TIMESOURCE) {
+ if (rel->from->type == DEG_NODE_TYPE_TIMESOURCE) {
/* HACK: time source nodes don't get "done" flag set/cleared. */
/* TODO: there will be other types in future, so iterators above
* need modifying.
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
index 0d56ce71c7d..51d4ed91419 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
@@ -35,10 +35,10 @@
extern "C" {
#include "DNA_listBase.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
-} /* extern "C" */
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
@@ -77,20 +77,18 @@ static const char *deg_debug_colors_light[] = {
#ifdef COLOR_SCHEME_NODE_TYPE
static const int deg_debug_node_type_color_map[][2] = {
- {DEPSNODE_TYPE_ROOT, 0},
- {DEPSNODE_TYPE_TIMESOURCE, 1},
- {DEPSNODE_TYPE_ID_REF, 2},
- {DEPSNODE_TYPE_SUBGRAPH, 3},
+ {DEG_NODE_TYPE_TIMESOURCE, 0},
+ {DEG_NODE_TYPE_ID_REF, 2},
/* Outer Types */
- {DEPSNODE_TYPE_PARAMETERS, 4},
- {DEPSNODE_TYPE_PROXY, 5},
- {DEPSNODE_TYPE_ANIMATION, 6},
- {DEPSNODE_TYPE_TRANSFORM, 7},
- {DEPSNODE_TYPE_GEOMETRY, 8},
- {DEPSNODE_TYPE_SEQUENCER, 9},
- {DEPSNODE_TYPE_SHADING, 10},
- {DEPSNODE_TYPE_CACHE, 11},
+ {DEG_NODE_TYPE_PARAMETERS, 2},
+ {DEG_NODE_TYPE_PROXY, 3},
+ {DEG_NODE_TYPE_ANIMATION, 4},
+ {DEG_NODE_TYPE_TRANSFORM, 5},
+ {DEG_NODE_TYPE_GEOMETRY, 6},
+ {DEG_NODE_TYPE_SEQUENCER, 7},
+ {DEG_NODE_TYPE_SHADING, 8},
+ {DEG_NODE_TYPE_CACHE, 9},
{-1, 0}
};
#endif
@@ -100,9 +98,9 @@ static int deg_debug_node_color_index(const DepsNode *node)
#ifdef COLOR_SCHEME_NODE_CLASS
/* Some special types. */
switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
+ case DEG_NODE_TYPE_ID_REF:
return 5;
- case DEPSNODE_TYPE_OPERATION:
+ case DEG_NODE_TYPE_OPERATION:
{
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->is_noop())
@@ -115,9 +113,9 @@ static int deg_debug_node_color_index(const DepsNode *node)
}
/* Do others based on class. */
switch (node->tclass) {
- case DEPSNODE_CLASS_OPERATION:
+ case DEG_NODE_CLASS_OPERATION:
return 4;
- case DEPSNODE_CLASS_COMPONENT:
+ case DEG_NODE_CLASS_COMPONENT:
return 1;
default:
return 9;
@@ -201,7 +199,7 @@ static void deg_debug_graphviz_node_color(const DebugContext &ctx,
const char *color_update = "dodgerblue3";
const char *color = color_default;
if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ if (node->tclass == DEG_NODE_CLASS_OPERATION) {
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
color = color_modified;
@@ -222,7 +220,7 @@ static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
float penwidth_update = 4.0f;
float penwidth = penwidth_default;
if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ if (node->tclass == DEG_NODE_CLASS_OPERATION) {
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
penwidth = penwidth_modified;
@@ -260,7 +258,7 @@ static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNod
{
const char *base_style = "filled"; /* default style */
if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ if (node->tclass == DEG_NODE_CLASS_OPERATION) {
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
base_style = "striped";
@@ -268,13 +266,13 @@ static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNod
}
}
switch (node->tclass) {
- case DEPSNODE_CLASS_GENERIC:
+ case DEG_NODE_CLASS_GENERIC:
deg_debug_fprintf(ctx, "\"%s\"", base_style);
break;
- case DEPSNODE_CLASS_COMPONENT:
+ case DEG_NODE_CLASS_COMPONENT:
deg_debug_fprintf(ctx, "\"%s\"", base_style);
break;
- case DEPSNODE_CLASS_OPERATION:
+ case DEG_NODE_CLASS_OPERATION:
deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style);
break;
}
@@ -286,13 +284,13 @@ static void deg_debug_graphviz_node_single(const DebugContext &ctx,
const char *shape = "box";
string name = node->identifier();
float priority = -1.0f;
- if (node->type == DEPSNODE_TYPE_ID_REF) {
+ if (node->type == DEG_NODE_TYPE_ID_REF) {
IDDepsNode *id_node = (IDDepsNode *)node;
char buf[256];
BLI_snprintf(buf, sizeof(buf), " (Layers: %u)", id_node->layers);
name += buf;
}
- if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
+ if (ctx.show_eval_priority && node->tclass == DEG_NODE_CLASS_OPERATION) {
priority = ((OperationDepsNode *)node)->eval_priority;
}
deg_debug_fprintf(ctx, "// %s\n", name.c_str());
@@ -322,7 +320,7 @@ static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
const DepsNode *node)
{
string name = node->identifier();
- if (node->type == DEPSNODE_TYPE_ID_REF) {
+ if (node->type == DEG_NODE_TYPE_ID_REF) {
IDDepsNode *id_node = (IDDepsNode *)node;
char buf[256];
BLI_snprintf(buf, sizeof(buf), " (Layers: %u)", id_node->layers);
@@ -363,7 +361,7 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
const DepsNode *node)
{
switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
+ case DEG_NODE_TYPE_ID_REF:
{
const IDDepsNode *id_node = (const IDDepsNode *)node;
if (BLI_ghash_size(id_node->components) == 0) {
@@ -380,30 +378,17 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
}
break;
}
- case DEPSNODE_TYPE_SUBGRAPH:
- {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- if (sub_node->graph) {
- deg_debug_graphviz_node_cluster_begin(ctx, node);
- deg_debug_graphviz_graph_nodes(ctx, sub_node->graph);
- deg_debug_graphviz_node_cluster_end(ctx);
- }
- else {
- deg_debug_graphviz_node_single(ctx, node);
- }
- break;
- }
- case DEPSNODE_TYPE_PARAMETERS:
- case DEPSNODE_TYPE_ANIMATION:
- case DEPSNODE_TYPE_TRANSFORM:
- case DEPSNODE_TYPE_PROXY:
- case DEPSNODE_TYPE_GEOMETRY:
- case DEPSNODE_TYPE_SEQUENCER:
- case DEPSNODE_TYPE_EVAL_POSE:
- case DEPSNODE_TYPE_BONE:
- case DEPSNODE_TYPE_SHADING:
- case DEPSNODE_TYPE_CACHE:
- case DEPSNODE_TYPE_EVAL_PARTICLES:
+ case DEG_NODE_TYPE_PARAMETERS:
+ case DEG_NODE_TYPE_ANIMATION:
+ case DEG_NODE_TYPE_TRANSFORM:
+ case DEG_NODE_TYPE_PROXY:
+ case DEG_NODE_TYPE_GEOMETRY:
+ case DEG_NODE_TYPE_SEQUENCER:
+ case DEG_NODE_TYPE_EVAL_POSE:
+ case DEG_NODE_TYPE_BONE:
+ case DEG_NODE_TYPE_SHADING:
+ case DEG_NODE_TYPE_CACHE:
+ case DEG_NODE_TYPE_EVAL_PARTICLES:
{
ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
if (!comp_node->operations.empty()) {
@@ -427,24 +412,19 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
{
switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
+ case DEG_NODE_TYPE_ID_REF:
{
const IDDepsNode *id_node = (const IDDepsNode *)node;
return BLI_ghash_size(id_node->components) > 0;
}
- case DEPSNODE_TYPE_SUBGRAPH:
- {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- return sub_node->graph != NULL;
- }
- case DEPSNODE_TYPE_PARAMETERS:
- case DEPSNODE_TYPE_ANIMATION:
- case DEPSNODE_TYPE_TRANSFORM:
- case DEPSNODE_TYPE_PROXY:
- case DEPSNODE_TYPE_GEOMETRY:
- case DEPSNODE_TYPE_SEQUENCER:
- case DEPSNODE_TYPE_EVAL_POSE:
- case DEPSNODE_TYPE_BONE:
+ case DEG_NODE_TYPE_PARAMETERS:
+ case DEG_NODE_TYPE_ANIMATION:
+ case DEG_NODE_TYPE_TRANSFORM:
+ case DEG_NODE_TYPE_PROXY:
+ case DEG_NODE_TYPE_GEOMETRY:
+ case DEG_NODE_TYPE_SEQUENCER:
+ case DEG_NODE_TYPE_EVAL_POSE:
+ case DEG_NODE_TYPE_BONE:
{
ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
return !comp_node->operations.empty();
@@ -458,14 +438,14 @@ static bool deg_debug_graphviz_is_owner(const DepsNode *node,
const DepsNode *other)
{
switch (node->tclass) {
- case DEPSNODE_CLASS_COMPONENT:
+ case DEG_NODE_CLASS_COMPONENT:
{
ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
if (comp_node->owner == other)
return true;
break;
}
- case DEPSNODE_CLASS_OPERATION:
+ case DEG_NODE_CLASS_OPERATION:
{
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->owner == other)
@@ -517,15 +497,12 @@ static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
const Depsgraph *graph)
{
- if (graph->root_node) {
- deg_debug_graphviz_node(ctx, graph->root_node);
- }
GHASH_FOREACH_BEGIN (DepsNode *, node, graph->id_hash)
{
deg_debug_graphviz_node(ctx, node);
}
GHASH_FOREACH_END();
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ TimeSourceDepsNode *time_source = graph->find_time_source();
if (time_source != NULL) {
deg_debug_graphviz_node(ctx, time_source);
}
@@ -546,7 +523,7 @@ static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
}
GHASH_FOREACH_END();
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ TimeSourceDepsNode *time_source = graph->find_time_source();
if (time_source != NULL) {
deg_debug_graphviz_node_relations(ctx, time_source);
}
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 9a4a35a5a35..aa21f0995be 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -69,26 +69,22 @@ static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
static DEG_EditorUpdateScenePreCb deg_editor_update_scene_pre_cb = NULL;
Depsgraph::Depsgraph()
- : root_node(NULL),
+ : time_source(NULL),
need_update(false),
layers(0)
{
BLI_spin_init(&lock);
id_hash = BLI_ghash_ptr_new("Depsgraph id hash");
- subgraphs = BLI_gset_ptr_new("Depsgraph subgraphs");
entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags");
}
Depsgraph::~Depsgraph()
{
- /* Free root node - it won't have been freed yet... */
clear_id_nodes();
- clear_subgraph_nodes();
BLI_ghash_free(id_hash, NULL, NULL);
- BLI_gset_free(subgraphs, NULL);
BLI_gset_free(entry_tags, NULL);
- if (this->root_node != NULL) {
- OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
+ if (time_source != NULL) {
+ OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode);
}
BLI_spin_end(&lock);
}
@@ -131,7 +127,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
/* Bone - generally, we just want the bone component... */
- *type = DEPSNODE_TYPE_BONE;
+ *type = DEG_NODE_TYPE_BONE;
*subdata = pchan->name;
return true;
@@ -141,7 +137,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
/* armature-level bone, but it ends up going to bone component anyway */
// TODO: the ID in thise case will end up being bArmature, not Object as needed!
- *type = DEPSNODE_TYPE_BONE;
+ *type = DEG_NODE_TYPE_BONE;
*subdata = bone->name;
//*id = ...
@@ -155,7 +151,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
if (BLI_findindex(&ob->constraints, con) != -1) {
/* object transform */
// XXX: for now, we can't address the specific constraint or the constraint stack...
- *type = DEPSNODE_TYPE_TRANSFORM;
+ *type = DEG_NODE_TYPE_TRANSFORM;
return true;
}
else if (ob->pose) {
@@ -163,7 +159,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (BLI_findindex(&pchan->constraints, con) != -1) {
/* bone transforms */
- *type = DEPSNODE_TYPE_BONE;
+ *type = DEG_NODE_TYPE_BONE;
*subdata = pchan->name;
return true;
}
@@ -178,7 +174,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
* so although we have unique ops for modifiers,
* we can't lump them together
*/
- *type = DEPSNODE_TYPE_BONE;
+ *type = DEG_NODE_TYPE_BONE;
//*subdata = md->name;
return true;
@@ -189,37 +185,44 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
/* Transforms props? */
if (prop) {
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
-
+ /* TODO(sergey): How to optimize this? */
if (strstr(prop_identifier, "location") ||
strstr(prop_identifier, "rotation") ||
- strstr(prop_identifier, "scale"))
+ strstr(prop_identifier, "scale") ||
+ strstr(prop_identifier, "matrix_"))
{
- *type = DEPSNODE_TYPE_TRANSFORM;
+ *type = DEG_NODE_TYPE_TRANSFORM;
+ return true;
+ }
+ else if (strstr(prop_identifier, "data")) {
+ /* We access object.data, most likely a geometry.
+ * Might be a bone tho..
+ */
+ *type = DEG_NODE_TYPE_GEOMETRY;
return true;
}
}
- // ...
}
else if (ptr->type == &RNA_ShapeKey) {
Key *key = (Key *)ptr->id.data;
/* ShapeKeys are currently handled as geometry on the geometry that owns it */
*id = key->from; // XXX
- *type = DEPSNODE_TYPE_PARAMETERS;
+ *type = DEG_NODE_TYPE_PARAMETERS;
return true;
}
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
Sequence *seq = (Sequence *)ptr->data;
/* Sequencer strip */
- *type = DEPSNODE_TYPE_SEQUENCER;
+ *type = DEG_NODE_TYPE_SEQUENCER;
*subdata = seq->name; // xxx?
return true;
}
if (prop) {
/* All unknown data effectively falls under "parameter evaluation" */
- *type = DEPSNODE_TYPE_PARAMETERS;
+ *type = DEG_NODE_TYPE_PARAMETERS;
return true;
}
@@ -256,72 +259,18 @@ static void id_node_deleter(void *value)
OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
}
-RootDepsNode *Depsgraph::add_root_node()
-{
- if (!root_node) {
- DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ROOT);
- root_node = (RootDepsNode *)factory->create_node(NULL, "", "Root (Scene)");
- }
- return root_node;
-}
-
-TimeSourceDepsNode *Depsgraph::find_time_source(const ID *id) const
-{
- /* Search for one attached to a particular ID? */
- if (id) {
- /* Check if it was added as a component
- * (as may be done for subgraphs needing timeoffset).
- */
- IDDepsNode *id_node = find_id_node(id);
- if (id_node) {
- // XXX: review this
-// return id_node->find_component(DEPSNODE_TYPE_TIMESOURCE);
- }
- BLI_assert(!"Not implemented yet");
- }
- else {
- /* Use "official" timesource. */
- return root_node->time_source;
- }
- return NULL;
-}
-
-SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id)
+TimeSourceDepsNode *Depsgraph::add_time_source()
{
- DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
- SubgraphDepsNode *subgraph_node =
- (SubgraphDepsNode *)factory->create_node(id, "", id->name + 2);
-
- /* Add to subnodes list. */
- BLI_gset_insert(subgraphs, subgraph_node);
-
- /* if there's an ID associated, add to ID-nodes lookup too */
- if (id) {
-#if 0
- /* XXX subgraph node is NOT a true IDDepsNode - what is this supposed to do? */
- // TODO: what to do if subgraph's ID has already been added?
- BLI_assert(!graph->find_id_node(id));
- graph->id_hash[id] = this;
-#endif
+ if (time_source == NULL) {
+ DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_TIMESOURCE);
+ time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", "Time Source");
}
-
- return subgraph_node;
-}
-
-void Depsgraph::remove_subgraph_node(SubgraphDepsNode *subgraph_node)
-{
- BLI_gset_remove(subgraphs, subgraph_node, NULL);
- OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
+ return time_source;
}
-void Depsgraph::clear_subgraph_nodes()
+TimeSourceDepsNode *Depsgraph::find_time_source() const
{
- GSET_FOREACH_BEGIN(SubgraphDepsNode *, subgraph_node, subgraphs)
- {
- OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
- }
- GSET_FOREACH_END();
- BLI_gset_clear(subgraphs, NULL);
+ return time_source;
}
IDDepsNode *Depsgraph::find_id_node(const ID *id) const
@@ -333,7 +282,7 @@ IDDepsNode *Depsgraph::add_id_node(ID *id, const char *name)
{
IDDepsNode *id_node = find_id_node(id);
if (!id_node) {
- DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ID_REF);
+ DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_ID_REF);
id_node = (IDDepsNode *)factory->create_node(id, "", name);
id->tag |= LIB_TAG_DOIT;
/* register */
@@ -342,16 +291,6 @@ IDDepsNode *Depsgraph::add_id_node(ID *id, const char *name)
return id_node;
}
-void Depsgraph::remove_id_node(const ID *id)
-{
- IDDepsNode *id_node = find_id_node(id);
- if (id_node) {
- /* unregister */
- BLI_ghash_remove(id_hash, id, NULL, NULL);
- OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
- }
-}
-
void Depsgraph::clear_id_nodes()
{
BLI_ghash_clear(id_hash, NULL, id_node_deleter);
@@ -360,15 +299,14 @@ void Depsgraph::clear_id_nodes()
/* Add new relationship between two nodes. */
DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
- eDepsRelation_Type type,
const char *description)
{
/* Create new relation, and add it to the graph. */
- DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, type, description);
+ DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
/* TODO(sergey): Find a better place for this. */
#ifdef WITH_OPENSUBDIV
ComponentDepsNode *comp_node = from->owner;
- if (comp_node->type == DEPSNODE_TYPE_GEOMETRY) {
+ if (comp_node->type == DEG_NODE_TYPE_GEOMETRY) {
IDDepsNode *id_to = to->owner->owner;
IDDepsNode *id_from = from->owner->owner;
if (id_to != id_from && (id_to->id->tag & LIB_TAG_ID_RECALC_ALL)) {
@@ -384,11 +322,10 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
/* Add new relation between two nodes */
DepsRelation *Depsgraph::add_new_relation(DepsNode *from, DepsNode *to,
- eDepsRelation_Type type,
const char *description)
{
/* Create new relation, and add it to the graph. */
- DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, type, description);
+ DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
return rel;
}
@@ -397,12 +334,10 @@ DepsRelation *Depsgraph::add_new_relation(DepsNode *from, DepsNode *to,
DepsRelation::DepsRelation(DepsNode *from,
DepsNode *to,
- eDepsRelation_Type type,
const char *description)
: from(from),
to(to),
name(description),
- type(type),
flag(0)
{
#ifndef NDEBUG
@@ -465,11 +400,10 @@ void Depsgraph::add_entry_tag(OperationDepsNode *node)
void Depsgraph::clear_all_nodes()
{
clear_id_nodes();
- clear_subgraph_nodes();
BLI_ghash_clear(id_hash, NULL, NULL);
- if (this->root_node) {
- OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
- root_node = NULL;
+ if (time_source != NULL) {
+ OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode);
+ time_source = NULL;
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index e668facd645..f72f8dd9311 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -49,10 +49,8 @@ struct PropertyRNA;
namespace DEG {
struct DepsNode;
-struct RootDepsNode;
struct TimeSourceDepsNode;
struct IDDepsNode;
-struct SubgraphDepsNode;
struct ComponentDepsNode;
struct OperationDepsNode;
@@ -79,12 +77,10 @@ struct DepsRelation {
/* relationship attributes */
const char *name; /* label for debugging */
- eDepsRelation_Type type; /* type */
int flag; /* (eDepsRelation_Flag) */
DepsRelation(DepsNode *from,
DepsNode *to,
- eDepsRelation_Type type,
const char *description);
~DepsRelation();
@@ -111,28 +107,20 @@ struct Depsgraph {
*/
DepsNode *find_node_from_pointer(const PointerRNA *ptr, const PropertyRNA *prop) const;
- RootDepsNode *add_root_node();
-
- TimeSourceDepsNode *find_time_source(const ID *id = NULL) const;
-
- SubgraphDepsNode *add_subgraph_node(const ID *id);
- void remove_subgraph_node(SubgraphDepsNode *subgraph_node);
- void clear_subgraph_nodes();
+ TimeSourceDepsNode *add_time_source();
+ TimeSourceDepsNode *find_time_source() const;
IDDepsNode *find_id_node(const ID *id) const;
IDDepsNode *add_id_node(ID *id, const char *name = "");
- void remove_id_node(const ID *id);
void clear_id_nodes();
/* Add new relationship between two nodes. */
DepsRelation *add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
- eDepsRelation_Type type,
const char *description);
DepsRelation *add_new_relation(DepsNode *from,
DepsNode *to,
- eDepsRelation_Type type,
const char *description);
/* Tag a specific node as needing updates. */
@@ -147,11 +135,8 @@ struct Depsgraph {
* (for quick lookups). */
GHash *id_hash;
- /* "root" node - the one where all evaluation enters from. */
- RootDepsNode *root_node;
-
- /* Subgraphs referenced in tree. */
- GSet *subgraphs;
+ /* Top-level time source node. */
+ TimeSourceDepsNode *time_source;
/* Indicates whether relations needs to be updated. */
bool need_update;
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 9952f714145..47bf5e7ecbb 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -34,12 +34,6 @@
// #define DEBUG_TIME
-extern "C" {
-#include "DNA_cachefile_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_object_force.h"
-
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -48,17 +42,22 @@ extern "C" {
# include "PIL_time_utildefines.h"
#endif
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_force.h"
+
#include "BKE_main.h"
#include "BKE_collision.h"
#include "BKE_effect.h"
#include "BKE_modifier.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
-} /* extern "C" */
-
#include "builder/deg_builder.h"
#include "builder/deg_builder_cycle.h"
#include "builder/deg_builder_nodes.h"
@@ -81,29 +80,29 @@ static DEG::eDepsNode_Type deg_build_scene_component_type(
eDepsSceneComponentType component)
{
switch (component) {
- case DEG_SCENE_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS;
- case DEG_SCENE_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION;
- case DEG_SCENE_COMP_SEQUENCER: return DEG::DEPSNODE_TYPE_SEQUENCER;
+ case DEG_SCENE_COMP_PARAMETERS: return DEG::DEG_NODE_TYPE_PARAMETERS;
+ case DEG_SCENE_COMP_ANIMATION: return DEG::DEG_NODE_TYPE_ANIMATION;
+ case DEG_SCENE_COMP_SEQUENCER: return DEG::DEG_NODE_TYPE_SEQUENCER;
}
- return DEG::DEPSNODE_TYPE_UNDEFINED;
+ return DEG::DEG_NODE_TYPE_UNDEFINED;
}
static DEG::eDepsNode_Type deg_build_object_component_type(
eDepsObjectComponentType component)
{
switch (component) {
- case DEG_OB_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS;
- case DEG_OB_COMP_PROXY: return DEG::DEPSNODE_TYPE_PROXY;
- case DEG_OB_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION;
- case DEG_OB_COMP_TRANSFORM: return DEG::DEPSNODE_TYPE_TRANSFORM;
- case DEG_OB_COMP_GEOMETRY: return DEG::DEPSNODE_TYPE_GEOMETRY;
- case DEG_OB_COMP_EVAL_POSE: return DEG::DEPSNODE_TYPE_EVAL_POSE;
- case DEG_OB_COMP_BONE: return DEG::DEPSNODE_TYPE_BONE;
- case DEG_OB_COMP_EVAL_PARTICLES: return DEG::DEPSNODE_TYPE_EVAL_PARTICLES;
- case DEG_OB_COMP_SHADING: return DEG::DEPSNODE_TYPE_SHADING;
- case DEG_OB_COMP_CACHE: return DEG::DEPSNODE_TYPE_CACHE;
+ case DEG_OB_COMP_PARAMETERS: return DEG::DEG_NODE_TYPE_PARAMETERS;
+ case DEG_OB_COMP_PROXY: return DEG::DEG_NODE_TYPE_PROXY;
+ case DEG_OB_COMP_ANIMATION: return DEG::DEG_NODE_TYPE_ANIMATION;
+ case DEG_OB_COMP_TRANSFORM: return DEG::DEG_NODE_TYPE_TRANSFORM;
+ case DEG_OB_COMP_GEOMETRY: return DEG::DEG_NODE_TYPE_GEOMETRY;
+ case DEG_OB_COMP_EVAL_POSE: return DEG::DEG_NODE_TYPE_EVAL_POSE;
+ case DEG_OB_COMP_BONE: return DEG::DEG_NODE_TYPE_BONE;
+ case DEG_OB_COMP_EVAL_PARTICLES: return DEG::DEG_NODE_TYPE_EVAL_PARTICLES;
+ case DEG_OB_COMP_SHADING: return DEG::DEG_NODE_TYPE_SHADING;
+ case DEG_OB_COMP_CACHE: return DEG::DEG_NODE_TYPE_CACHE;
}
- return DEG::DEPSNODE_TYPE_UNDEFINED;
+ return DEG::DEG_NODE_TYPE_UNDEFINED;
}
static DEG::DepsNodeHandle *get_handle(DepsNodeHandle *handle)
@@ -121,7 +120,6 @@ void DEG_add_scene_relation(DepsNodeHandle *handle,
DEG::DepsNodeHandle *deg_handle = get_handle(handle);
deg_handle->builder->add_node_handle_relation(comp_key,
deg_handle,
- DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
description);
}
@@ -135,7 +133,6 @@ void DEG_add_object_relation(DepsNodeHandle *handle,
DEG::DepsNodeHandle *deg_handle = get_handle(handle);
deg_handle->builder->add_node_handle_relation(comp_key,
deg_handle,
- DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
description);
}
@@ -149,7 +146,6 @@ void DEG_add_object_cache_relation(DepsNodeHandle *handle,
DEG::DepsNodeHandle *deg_handle = get_handle(handle);
deg_handle->builder->add_node_handle_relation(comp_key,
deg_handle,
- DEG::DEPSREL_TYPE_CACHE,
description);
}
@@ -167,10 +163,16 @@ void DEG_add_bone_relation(DepsNodeHandle *handle,
*/
deg_handle->builder->add_node_handle_relation(comp_key,
deg_handle,
- DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
description);
}
+struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *handle)
+{
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ DEG::DepsgraphRelationBuilder *relation_builder = deg_handle->builder;
+ return reinterpret_cast<Depsgraph *>(relation_builder->getGraph());
+}
+
void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
@@ -205,28 +207,14 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
/* 1) Generate all the nodes in the graph first */
DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph);
- /* create root node for scene first
- * - this way it should be the first in the graph,
- * reflecting its role as the entrypoint
- */
- node_builder.add_root_node();
+ node_builder.begin_build(bmain);
node_builder.build_scene(bmain, scene);
/* 2) Hook up relationships between operations - to determine evaluation
* order.
*/
DEG::DepsgraphRelationBuilder relation_builder(deg_graph);
- /* Hook scene up to the root node as entrypoint to graph. */
- /* XXX what does this relation actually mean?
- * it doesnt add any operations anyway and is not clear what part of the
- * scene is to be connected.
- */
-#if 0
- relation_builder.add_relation(RootKey(),
- IDKey(scene),
- DEPSREL_TYPE_ROOT_TO_ACTIVE,
- "Root to Active Scene");
-#endif
+ relation_builder.begin_build(bmain);
relation_builder.build_scene(bmain, scene);
/* Detect and solve cycles. */
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index d3b48930779..388b692d742 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -35,11 +35,11 @@
extern "C" {
#include "DNA_scene_types.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
-} /* extern "C" */
#include "intern/eval/deg_eval_debug.h"
#include "intern/depsgraph_intern.h"
@@ -165,7 +165,7 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
return false;
}
foreach (DEG::DepsRelation *rel, node->outlinks) {
- if (rel->to->type == DEG::DEPSNODE_TYPE_OPERATION) {
+ if (rel->to->type == DEG::DEG_NODE_TYPE_OPERATION) {
DEG::OperationDepsNode *to = (DEG::OperationDepsNode *)rel->to;
BLI_assert(to->num_links_pending < to->inlinks.size());
++to->num_links_pending;
@@ -177,7 +177,7 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
int num_links_pending = 0;
foreach (DEG::DepsRelation *rel, node->inlinks) {
- if (rel->from->type == DEG::DEPSNODE_TYPE_OPERATION) {
+ if (rel->from->type == DEG::DEG_NODE_TYPE_OPERATION) {
++num_links_pending;
}
}
@@ -232,7 +232,7 @@ void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
}
GHASH_FOREACH_END();
- DEG::TimeSourceDepsNode *time_source = deg_graph->find_time_source(NULL);
+ DEG::TimeSourceDepsNode *time_source = deg_graph->find_time_source();
if (time_source != NULL) {
tot_rels += time_source->inlinks.size();
}
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index c41f28b07e8..85a0d336d28 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -32,17 +32,17 @@
#include "MEM_guardedalloc.h"
-extern "C" {
-#include "DNA_scene_types.h"
-
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+extern "C" {
+#include "DNA_scene_types.h"
+
#include "BKE_depsgraph.h"
#include "BKE_scene.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
-} /* extern "C" */
#include "intern/eval/deg_eval.h"
#include "intern/eval/deg_eval_flush.h"
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 7f2f6a65f5e..e58a7a32407 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -35,9 +35,9 @@
extern "C" {
#include "BKE_idcode.h"
#include "BKE_main.h"
+} /* extern "C" */
#include "DEG_depsgraph_query.h"
-} /* extern "C" */
#include "intern/depsgraph_intern.h"
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index e8ed03666a6..5adcb3a11b3 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -34,15 +34,16 @@
#include <cstring> /* required for memset */
#include <queue>
-extern "C" {
#include "BLI_utildefines.h"
+#include "BLI_task.h"
+#include "BLI_listbase.h"
+extern "C" {
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
-#include "BLI_task.h"
#include "BKE_idcode.h"
#include "BKE_library.h"
@@ -52,12 +53,12 @@ extern "C" {
#define new new_
#include "BKE_screen.h"
#undef new
+} /* extern "C" */
#include "DEG_depsgraph.h"
-} /* extern "C" */
+#include "intern/builder/deg_builder.h"
#include "intern/eval/deg_eval_flush.h"
-
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
@@ -108,7 +109,7 @@ void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag)
* nodes for update after relations update and after layer
* visibility changes.
*/
- short idtype = GS(id->name);
+ ID_Type idtype = GS(id->name);
if (idtype == ID_OB) {
Object *object = (Object *)id;
object->recalc |= (flag & OB_RECALC_ALL);
@@ -276,15 +277,20 @@ void DEG_ids_flush_tagged(Main *bmain)
scene != NULL;
scene = (Scene *)scene->id.next)
{
- /* TODO(sergey): Only visible scenes? */
- if (scene->depsgraph != NULL) {
- DEG::deg_graph_flush_updates(
- bmain,
- reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph));
- }
+ DEG_scene_flush_update(bmain, scene);
}
}
+void DEG_scene_flush_update(Main *bmain, Scene *scene)
+{
+ if (scene->depsgraph == NULL) {
+ return;
+ }
+ DEG::deg_graph_flush_updates(
+ bmain,
+ reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph));
+}
+
/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
{
@@ -336,7 +342,7 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
{
id_node->tag_update(graph);
DEG::ComponentDepsNode *anim_comp =
- id_node->find_component(DEG::DEPSNODE_TYPE_ANIMATION);
+ id_node->find_component(DEG::DEG_NODE_TYPE_ANIMATION);
if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) {
anim_comp->tag_update(graph);
}
@@ -346,6 +352,37 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
GHASH_FOREACH_END();
}
scene->lay_updated |= graph->layers;
+ /* If graph is tagged for update, we don't need to bother with updates here,
+ * nodes will be re-created.
+ */
+ if (graph->need_update) {
+ return;
+ }
+ /* Special trick to get local view to work. */
+ LINKLIST_FOREACH (Base *, base, &scene->base) {
+ Object *object = base->object;
+ DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
+ id_node->layers = 0;
+ }
+ LINKLIST_FOREACH (Base *, base, &scene->base) {
+ Object *object = base->object;
+ DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
+ id_node->layers |= base->lay;
+ if (object == scene->camera) {
+ /* Camera should always be updated, it used directly by viewport. */
+ id_node->layers |= (unsigned int)(-1);
+ }
+ }
+ DEG::deg_graph_build_flush_layers(graph);
+ LINKLIST_FOREACH (Base *, base, &scene->base) {
+ Object *object = base->object;
+ DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
+ GHASH_FOREACH_BEGIN(DEG::ComponentDepsNode *, comp, id_node->components)
+ {
+ id_node->layers |= comp->layers;
+ }
+ GHASH_FOREACH_END();
+ }
}
void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
index 4ce91516c84..e177c8c8ec0 100644
--- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -32,12 +32,11 @@
#include <cstdlib> // for BLI_assert()
-extern "C" {
+
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "DEG_depsgraph.h"
-} /* extern "C" */
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
@@ -98,37 +97,31 @@ static const char *stringify_opcode(eDepsOperation_Code opcode)
#define STRINGIFY_OPCODE(name) case DEG_OPCODE_##name: return #name
STRINGIFY_OPCODE(OPERATION);
STRINGIFY_OPCODE(PLACEHOLDER);
- STRINGIFY_OPCODE(NOOP);
STRINGIFY_OPCODE(ANIMATION);
STRINGIFY_OPCODE(DRIVER);
- //STRINGIFY_OPCODE(PROXY);
STRINGIFY_OPCODE(TRANSFORM_LOCAL);
STRINGIFY_OPCODE(TRANSFORM_PARENT);
STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS);
- //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_INIT);
- //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINT);
- //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_DONE);
STRINGIFY_OPCODE(RIGIDBODY_REBUILD);
STRINGIFY_OPCODE(RIGIDBODY_SIM);
STRINGIFY_OPCODE(TRANSFORM_RIGIDBODY);
STRINGIFY_OPCODE(TRANSFORM_FINAL);
STRINGIFY_OPCODE(OBJECT_UBEREVAL);
STRINGIFY_OPCODE(GEOMETRY_UBEREVAL);
- STRINGIFY_OPCODE(GEOMETRY_MODIFIER);
- STRINGIFY_OPCODE(GEOMETRY_PATH);
STRINGIFY_OPCODE(POSE_INIT);
+ STRINGIFY_OPCODE(POSE_INIT_IK);
STRINGIFY_OPCODE(POSE_DONE);
STRINGIFY_OPCODE(POSE_IK_SOLVER);
STRINGIFY_OPCODE(POSE_SPLINE_IK_SOLVER);
STRINGIFY_OPCODE(BONE_LOCAL);
STRINGIFY_OPCODE(BONE_POSE_PARENT);
STRINGIFY_OPCODE(BONE_CONSTRAINTS);
- //STRINGIFY_OPCODE(BONE_CONSTRAINTS_INIT);
- //STRINGIFY_OPCODE(BONE_CONSTRAINT);
- //STRINGIFY_OPCODE(BONE_CONSTRAINTS_DONE);
STRINGIFY_OPCODE(BONE_READY);
STRINGIFY_OPCODE(BONE_DONE);
STRINGIFY_OPCODE(PSYS_EVAL);
+ STRINGIFY_OPCODE(PSYS_EVAL_INIT);
+ STRINGIFY_OPCODE(MASK_ANIMATION);
+ STRINGIFY_OPCODE(MASK_EVAL);
case DEG_NUM_OPCODES: return "SpecialCase";
#undef STRINGIFY_OPCODE
@@ -145,7 +138,7 @@ DepsOperationStringifier::DepsOperationStringifier()
const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode)
{
- BLI_assert((opcode > 0) && (opcode < DEG_NUM_OPCODES));
+ 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/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
index effd34a0eb9..ef7b32a8d83 100644
--- a/source/blender/depsgraph/intern/depsgraph_types.h
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -44,9 +44,6 @@
#include <string>
#include <vector>
-using std::string;
-using std::vector;
-
struct bAction;
struct ChannelDriver;
struct ModifierData;
@@ -56,6 +53,9 @@ struct FCurve;
namespace DEG {
+using std::string;
+using std::vector;
+
/* Evaluation Operation for atomic operation */
// XXX: move this to another header that can be exposed?
typedef function<void(struct EvaluationContext *)> DepsEvalOperationCb;
@@ -67,74 +67,66 @@ typedef enum eDepsNode_Class {
/* Types generally unassociated with user-visible entities,
* but needed for graph functioning.
*/
- DEPSNODE_CLASS_GENERIC = 0,
+ DEG_NODE_CLASS_GENERIC = 0,
/* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring
* certain types of evaluation behavior.
*/
- DEPSNODE_CLASS_COMPONENT = 1,
+ DEG_NODE_CLASS_COMPONENT = 1,
/* [Inner Node] A glorified function-pointer/callback for scheduling up
* evaluation operations for components, subject to relationship
* requirements.
*/
- DEPSNODE_CLASS_OPERATION = 2,
+ DEG_NODE_CLASS_OPERATION = 2,
} eDepsNode_Class;
/* Types of Nodes */
typedef enum eDepsNode_Type {
/* Fallback type for invalid return value */
- DEPSNODE_TYPE_UNDEFINED = -1,
+ DEG_NODE_TYPE_UNDEFINED = -1,
/* Inner Node (Operation) */
- DEPSNODE_TYPE_OPERATION = 0,
+ DEG_NODE_TYPE_OPERATION = 0,
/* **** Generic Types **** */
- /* "Current Scene" - basically whatever kicks off the evaluation process. */
- DEPSNODE_TYPE_ROOT = 1,
/* Time-Source */
- DEPSNODE_TYPE_TIMESOURCE = 2,
+ DEG_NODE_TYPE_TIMESOURCE,
/* ID-Block reference - used as landmarks/collection point for components,
* but not usually part of main graph.
*/
- DEPSNODE_TYPE_ID_REF = 3,
- /* Isolated sub-graph - used for keeping instanced data separate from
- * instances using them.
- */
- DEPSNODE_TYPE_SUBGRAPH = 4,
+ DEG_NODE_TYPE_ID_REF,
/* **** Outer Types **** */
/* Parameters Component - Default when nothing else fits
* (i.e. just SDNA property setting).
*/
- DEPSNODE_TYPE_PARAMETERS = 11,
- /* Generic "Proxy-Inherit" Component
- * XXX: Also for instancing of subgraphs?
- */
- DEPSNODE_TYPE_PROXY = 12,
+ DEG_NODE_TYPE_PARAMETERS,
+ /* Generic "Proxy-Inherit" Component. */
+ DEG_NODE_TYPE_PROXY,
/* Animation Component
*
* XXX: merge in with parameters?
*/
- DEPSNODE_TYPE_ANIMATION = 13,
+ DEG_NODE_TYPE_ANIMATION,
/* Transform Component (Parenting/Constraints) */
- DEPSNODE_TYPE_TRANSFORM = 14,
+ DEG_NODE_TYPE_TRANSFORM,
/* Geometry Component (DerivedMesh/Displist) */
- DEPSNODE_TYPE_GEOMETRY = 15,
+ DEG_NODE_TYPE_GEOMETRY,
/* Sequencer Component (Scene Only) */
- DEPSNODE_TYPE_SEQUENCER = 16,
+ DEG_NODE_TYPE_SEQUENCER,
/* **** Evaluation-Related Outer Types (with Subdata) **** */
/* Pose Component - Owner/Container of Bones Eval */
- DEPSNODE_TYPE_EVAL_POSE = 21,
+ DEG_NODE_TYPE_EVAL_POSE,
/* Bone Component - Child/Subcomponent of Pose */
- DEPSNODE_TYPE_BONE = 22,
+ DEG_NODE_TYPE_BONE,
/* Particle Systems Component */
- DEPSNODE_TYPE_EVAL_PARTICLES = 23,
+ DEG_NODE_TYPE_EVAL_PARTICLES,
/* Material Shading Component */
- DEPSNODE_TYPE_SHADING = 24,
+ DEG_NODE_TYPE_SHADING,
/* Cache Component */
- DEPSNODE_TYPE_CACHE = 25,
+ DEG_NODE_TYPE_CACHE,
} eDepsNode_Type;
/* Identifiers for common operations (as an enum). */
@@ -147,8 +139,6 @@ typedef enum eDepsOperation_Code {
// XXX: Placeholder while porting depsgraph code
DEG_OPCODE_PLACEHOLDER,
- DEG_OPCODE_NOOP,
-
/* Animation, Drivers, etc. ------------------------ */
/* NLA + Action */
@@ -157,9 +147,6 @@ typedef enum eDepsOperation_Code {
/* Driver */
DEG_OPCODE_DRIVER,
- /* Proxy Inherit? */
- //DEG_OPCODE_PROXY,
-
/* Transform --------------------------------------- */
/* Transform entry point - local transforms only */
@@ -170,9 +157,6 @@ typedef enum eDepsOperation_Code {
/* Constraints */
DEG_OPCODE_TRANSFORM_CONSTRAINTS,
- //DEG_OPCODE_TRANSFORM_CONSTRAINTS_INIT,
- //DEG_OPCODE_TRANSFORM_CONSTRAINT,
- //DEG_OPCODE_TRANSFORM_CONSTRAINTS_DONE,
/* Rigidbody Sim - Perform Sim */
DEG_OPCODE_RIGIDBODY_REBUILD,
@@ -192,17 +176,14 @@ typedef enum eDepsOperation_Code {
/* XXX: Placeholder - UberEval */
DEG_OPCODE_GEOMETRY_UBEREVAL,
- /* Modifier */
- DEG_OPCODE_GEOMETRY_MODIFIER,
-
- /* Curve Objects - Path Calculation (used for path-following tools, */
- DEG_OPCODE_GEOMETRY_PATH,
-
/* Pose -------------------------------------------- */
- /* Init IK Trees, etc. */
+ /* Init pose, clear flags, etc. */
DEG_OPCODE_POSE_INIT,
+ /* Initialize IK solver related pose stuff. */
+ DEG_OPCODE_POSE_INIT_IK,
+
/* Free IK Trees + Compute Deform Matrices */
DEG_OPCODE_POSE_DONE,
@@ -220,9 +201,6 @@ typedef enum eDepsOperation_Code {
/* Constraints */
DEG_OPCODE_BONE_CONSTRAINTS,
- //DEG_OPCODE_BONE_CONSTRAINTS_INIT,
- //DEG_OPCODE_BONE_CONSTRAINT,
- //DEG_OPCODE_BONE_CONSTRAINTS_DONE,
/* Bone transforms are ready
*
@@ -241,8 +219,13 @@ typedef enum eDepsOperation_Code {
/* Particles --------------------------------------- */
/* XXX: placeholder - Particle System eval */
+ DEG_OPCODE_PSYS_EVAL_INIT,
DEG_OPCODE_PSYS_EVAL,
+ /* Masks ------------------------------------------- */
+ DEG_OPCODE_MASK_ANIMATION,
+ DEG_OPCODE_MASK_EVAL,
+
DEG_NUM_OPCODES,
} eDepsOperation_Code;
@@ -258,83 +241,4 @@ protected:
/* String defines for these opcodes, defined in depsgraph_type_defines.cpp */
extern DepsOperationStringifier DEG_OPNAMES;
-/* Type of operation */
-typedef enum eDepsOperation_Type {
- /* **** Primary operation types **** */
-
- /* Initialise evaluation data */
- DEPSOP_TYPE_INIT = 0,
- /* Standard evaluation step */
- DEPSOP_TYPE_EXEC = 1,
- /* Cleanup evaluation data + flush results */
- DEPSOP_TYPE_POST = 2,
-
- /* **** Additional operation types **** */
- /* Indicator for outputting a temporary result that other components
- * can use. // XXX?
- */
- DEPSOP_TYPE_OUT = 3,
- /* Indicator for things like IK Solvers and Rigidbody Sim steps which
- * modify final results of separate entities at once.
- */
- DEPSOP_TYPE_SIM = 4,
- /* Rebuild internal evaluation data - used for Rigidbody Reset and
- * Armature Rebuild-On-Load.
- */
- DEPSOP_TYPE_REBUILD = 5,
-} eDepsOperation_Type;
-
-/* Types of relationships between nodes
- *
- * This is used to provide additional hints to use when filtering
- * the graph, so that we can go without doing more extensive
- * data-level checks...
- */
-typedef enum eDepsRelation_Type {
- /* relationship type unknown/irrelevant */
- DEPSREL_TYPE_STANDARD = 0,
-
- /* root -> active scene or entity (screen, image, etc.) */
- DEPSREL_TYPE_ROOT_TO_ACTIVE,
-
- /* general datablock dependency */
- DEPSREL_TYPE_DATABLOCK,
-
- /* time dependency */
- DEPSREL_TYPE_TIME,
-
- /* component depends on results of another */
- DEPSREL_TYPE_COMPONENT_ORDER,
-
- /* relationship is just used to enforce ordering of operations
- * (e.g. "init()" callback done before "exec() and "cleanup()")
- */
- DEPSREL_TYPE_OPERATION,
-
- /* relationship results from a property driver affecting property */
- DEPSREL_TYPE_DRIVER,
-
- /* relationship is something driver depends on */
- DEPSREL_TYPE_DRIVER_TARGET,
-
- /* relationship is used for transform stack
- * (e.g. parenting, user transforms, constraints)
- */
- DEPSREL_TYPE_TRANSFORM,
-
- /* relationship is used for geometry evaluation
- * (e.g. metaball "motherball" or modifiers)
- */
- DEPSREL_TYPE_GEOMETRY_EVAL,
-
- /* relationship is used to trigger a post-change validity updates */
- DEPSREL_TYPE_UPDATE,
-
- /* relationship is used to trigger editor/screen updates */
- DEPSREL_TYPE_UPDATE_UI,
-
- /* cache dependency */
- DEPSREL_TYPE_CACHE,
-} eDepsRelation_Type;
-
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index e926f83bcbe..98b10718404 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -34,16 +34,16 @@
#include "PIL_time.h"
-extern "C" {
#include "BLI_utildefines.h"
#include "BLI_task.h"
#include "BLI_ghash.h"
+extern "C" {
#include "BKE_depsgraph.h"
#include "BKE_global.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
-} /* extern "C" */
#include "atomic_ops.h"
@@ -53,6 +53,7 @@ extern "C" {
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
/* Unfinished and unused, and takes quite some pre-processing time. */
@@ -94,105 +95,40 @@ static void deg_task_run_func(TaskPool *pool,
/* Should only be the case for NOOPs, which never get to this point. */
BLI_assert(node->evaluate);
- while (true) {
- /* Get context. */
- /* TODO: Who initialises this? "Init" operations aren't able to
- * initialise it!!!
- */
- /* TODO(sergey): We don't use component contexts at this moment. */
- /* ComponentDepsNode *comp = node->owner; */
- BLI_assert(node->owner != NULL);
-
- /* Since we're not leaving the thread for until the graph branches it is
- * possible to have NO-OP on the way. for which evaluate() will be NULL.
- * but that's all fine, we'll just scheduler it's children.
- */
- if (node->evaluate) {
+ /* Get context. */
+ /* TODO: Who initialises this? "Init" operations aren't able to
+ * initialise it!!!
+ */
+ /* TODO(sergey): We don't use component contexts at this moment. */
+ /* ComponentDepsNode *comp = node->owner; */
+ BLI_assert(node->owner != NULL);
+
+ /* Since we're not leaving the thread for until the graph branches it is
+ * possible to have NO-OP on the way. for which evaluate() will be NULL.
+ * but that's all fine, we'll just scheduler it's children.
+ */
+ if (node->evaluate) {
/* Take note of current time. */
#ifdef USE_DEBUGGER
- double start_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_started(state->graph, node);
+ double start_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_started(state->graph, node);
#endif
- /* Perform operation. */
- node->evaluate(state->eval_ctx);
+ /* Perform operation. */
+ node->evaluate(state->eval_ctx);
/* Note how long this took. */
#ifdef USE_DEBUGGER
- double end_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_completed(state->graph,
- node,
- end_time - start_time);
+ double end_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_completed(state->graph,
+ node,
+ end_time - start_time);
#endif
- }
-
- /* If there's only one outgoing link we try to immediately switch to
- * that node evaluation, without leaving the thread.
- *
- * It's only doable if the child don't have extra relations or all they
- * are satisfied.
- *
- * TODO(sergey): Checks here can be de-duplicated with the ones from
- * schedule_node(), however, how to do it nicely?
- */
- if (node->outlinks.size() == 1) {
- DepsRelation *rel = node->outlinks[0];
- OperationDepsNode *child = (OperationDepsNode *)rel->to;
- BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
- if (!child->scheduled) {
- unsigned int id_layers = child->owner->owner->layers;
- if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
- (id_layers & state->layers) != 0))
- {
- /* Node does not need an update, so can;t continue with the
- * chain and need to switch to another one by leaving the
- * thread.
- */
- break;
- }
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- BLI_assert(child->num_links_pending > 0);
- atomic_sub_and_fetch_uint32(&child->num_links_pending, 1);
- }
- if (child->num_links_pending == 0) {
- bool is_scheduled = atomic_fetch_and_or_uint8(
- (uint8_t *)&child->scheduled, (uint8_t)true);
- if (!is_scheduled) {
- /* Node was not scheduled, switch to it! */
- node = child;
- }
- else {
- /* Someone else scheduled the node, leaving us
- * unemployed in this thread, we're leaving.
- */
- break;
- }
- }
- else {
- /* There are other dependencies on the child, can't do
- * anything in the current thread.
- */
- break;
- }
- }
- else {
- /* Happens when having cyclic dependencies.
- *
- * Nothing to do here, single child was already scheduled, we
- * can leave the thread now.
- */
- break;
- }
- }
- else {
- /* TODO(sergey): It's possible to use one of the outgoing relations
- * as a chain which we'll try to keep alive, but it's a bit more
- * involved change.
- */
- schedule_children(pool, state->graph, node, state->layers, thread_id);
- break;
- }
}
+
+ BLI_task_pool_delayed_push_begin(pool, thread_id);
+ schedule_children(pool, state->graph, node, state->layers, thread_id);
+ BLI_task_pool_delayed_push_end(pool, thread_id);
}
typedef struct CalculatePengindData {
@@ -216,7 +152,7 @@ static void calculate_pending_func(void *data_v, int i)
(node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
{
foreach (DepsRelation *rel, node->inlinks) {
- if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
+ if (rel->from->type == DEG_NODE_TYPE_OPERATION &&
(rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
{
OperationDepsNode *from = (OperationDepsNode *)rel->from;
@@ -261,7 +197,7 @@ static void calculate_eval_priority(OperationDepsNode *node)
foreach (DepsRelation *rel, node->outlinks) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
- BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
+ BLI_assert(to->type == DEG_NODE_TYPE_OPERATION);
calculate_eval_priority(to);
node->eval_priority += to->eval_priority;
}
@@ -304,7 +240,7 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers,
deg_task_run_func,
node,
false,
- TASK_PRIORITY_LOW,
+ TASK_PRIORITY_HIGH,
thread_id);
}
}
@@ -329,7 +265,7 @@ static void schedule_children(TaskPool *pool,
{
foreach (DepsRelation *rel, node->outlinks) {
OperationDepsNode *child = (OperationDepsNode *)rel->to;
- BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+ BLI_assert(child->type == DEG_NODE_TYPE_OPERATION);
if (child->scheduled) {
/* Happens when having cyclic dependencies. */
continue;
@@ -362,6 +298,11 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
return;
}
+ DEG_DEBUG_PRINTF("%s: layers:%u, graph->layers:%u\n",
+ __func__,
+ layers,
+ graph->layers);
+
/* Set time for the current graph evaluation context. */
TimeSourceDepsNode *time_src = graph->find_time_source();
eval_ctx->ctime = time_src->cfra;
@@ -372,12 +313,19 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
state.graph = graph;
state.layers = layers;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state);
+ TaskScheduler *task_scheduler;
+ bool need_free_scheduler;
if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- BLI_pool_set_num_threads(task_pool, 1);
+ task_scheduler = BLI_task_scheduler_create(1);
+ need_free_scheduler = true;
}
+ else {
+ task_scheduler = BLI_task_scheduler_get();
+ need_free_scheduler = false;
+ }
+
+ TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state);
calculate_pending_parents(graph, layers);
@@ -404,6 +352,10 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
/* Clear any uncleared tags - just in case. */
deg_graph_clear_tags(graph);
+
+ if (need_free_scheduler) {
+ BLI_task_scheduler_free(task_scheduler);
+ }
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
index 060544a4407..23f4adbaacd 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
@@ -34,16 +34,16 @@
#include <cstring> /* required for STREQ later on. */
-extern "C" {
#include "BLI_listbase.h"
#include "BLI_ghash.h"
-#include "DEG_depsgraph_debug.h"
-
+extern "C" {
#include "WM_api.h"
#include "WM_types.h"
} /* extern "C" */
+#include "DEG_depsgraph_debug.h"
+
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index 7c6c25bef0d..0adbadeebba 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -35,16 +35,16 @@
// TODO(sergey): Use some sort of wrapper.
#include <deque>
-extern "C" {
-#include "DNA_object_types.h"
-
#include "BLI_utildefines.h"
#include "BLI_task.h"
#include "BLI_ghash.h"
-#include "DEG_depsgraph.h"
+extern "C" {
+#include "DNA_object_types.h"
} /* extern "C" */
+#include "DEG_depsgraph.h"
+
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
@@ -54,6 +54,12 @@ extern "C" {
namespace DEG {
+enum {
+ COMPONENT_STATE_NONE = 0,
+ COMPONENT_STATE_SCHEDULED = 1,
+ COMPONENT_STATE_DONE = 2,
+};
+
namespace {
// TODO(sergey): De-duplicate with depsgraph_tag,cc
@@ -83,7 +89,7 @@ static void flush_init_func(void *data_v, int i)
ComponentDepsNode *comp_node = node->owner;
IDDepsNode *id_node = comp_node->owner;
id_node->done = 0;
- comp_node->done = 0;
+ comp_node->done = COMPONENT_STATE_NONE;
node->scheduled = false;
}
@@ -139,18 +145,18 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
IDDepsNode *id_node = comp_node->owner;
ID *id = id_node->id;
- if(id_node->done == 0) {
+ if (id_node->done == 0) {
deg_editors_id_update(bmain, id);
lib_id_recalc_tag(bmain, id);
/* TODO(sergey): For until we've got proper data nodes in the graph. */
lib_id_recalc_data_tag(bmain, id);
}
- if(comp_node->done == 0) {
+ if (comp_node->done != COMPONENT_STATE_DONE) {
Object *object = NULL;
if (GS(id->name) == ID_OB) {
object = (Object *)id;
- if(id_node->done == 0) {
+ if (id_node->done == 0) {
++num_flushed_objects;
}
}
@@ -164,22 +170,55 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
* 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;
+ switch (comp_node->type) {
+ case DEG_NODE_TYPE_UNDEFINED:
+ case DEG_NODE_TYPE_OPERATION:
+ case DEG_NODE_TYPE_TIMESOURCE:
+ case DEG_NODE_TYPE_ID_REF:
+ case DEG_NODE_TYPE_PARAMETERS:
+ case DEG_NODE_TYPE_SEQUENCER:
+ /* Ignore, does not translate to object component. */
+ break;
+ case DEG_NODE_TYPE_ANIMATION:
+ object->recalc |= OB_RECALC_TIME;
+ break;
+ case DEG_NODE_TYPE_TRANSFORM:
+ object->recalc |= OB_RECALC_OB;
+ break;
+ case DEG_NODE_TYPE_GEOMETRY:
+ case DEG_NODE_TYPE_EVAL_POSE:
+ case DEG_NODE_TYPE_BONE:
+ case DEG_NODE_TYPE_EVAL_PARTICLES:
+ case DEG_NODE_TYPE_SHADING:
+ case DEG_NODE_TYPE_CACHE:
+ case DEG_NODE_TYPE_PROXY:
+ object->recalc |= OB_RECALC_DATA;
+ break;
}
- else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
- object->recalc |= OB_RECALC_OB;
- }
- else {
- object->recalc |= OB_RECALC_DATA;
+ }
+ /* When some target changes bone, we might need to re-run the
+ * whole IK solver, otherwise result might be unpredictable.
+ */
+ if (comp_node->type == DEG_NODE_TYPE_BONE) {
+ ComponentDepsNode *pose_comp =
+ id_node->find_component(DEG_NODE_TYPE_EVAL_POSE);
+ BLI_assert(pose_comp != NULL);
+ if (pose_comp->done == COMPONENT_STATE_NONE) {
+ queue.push_front(pose_comp->get_entry_operation());
+ pose_comp->done = COMPONENT_STATE_SCHEDULED;
}
}
}
id_node->done = 1;
- comp_node->done = 1;
+ comp_node->done = COMPONENT_STATE_DONE;
/* Flush to nodes along links... */
+ /* TODO(sergey): This is mainly giving speedup due ot less queue pushes, which
+ * reduces number of memory allocations.
+ *
+ * We should try solve the allocation issue instead of doing crazy things here.
+ */
if (node->outlinks.size() == 1) {
OperationDepsNode *to_node = (OperationDepsNode *)node->outlinks[0]->to;
if (to_node->scheduled == false) {
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc
index 57b25c10670..a15317586c1 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node.cc
@@ -41,15 +41,14 @@ extern "C" {
#include "DNA_anim_types.h"
#include "BKE_animsys.h"
+}
#include "DEG_depsgraph.h"
-}
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
-#include "util/deg_util_hash.h"
namespace DEG {
@@ -61,12 +60,12 @@ namespace DEG {
DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname)
{
this->type = type;
- if (type == DEPSNODE_TYPE_OPERATION)
- this->tclass = DEPSNODE_CLASS_OPERATION;
- else if (type < DEPSNODE_TYPE_PARAMETERS)
- this->tclass = DEPSNODE_CLASS_GENERIC;
+ if (type == DEG_NODE_TYPE_OPERATION)
+ this->tclass = DEG_NODE_CLASS_OPERATION;
+ else if (type < DEG_NODE_TYPE_PARAMETERS)
+ this->tclass = DEG_NODE_CLASS_GENERIC;
else
- this->tclass = DEPSNODE_CLASS_COMPONENT;
+ this->tclass = DEG_NODE_CLASS_COMPONENT;
this->tname = tname;
}
@@ -110,34 +109,9 @@ void TimeSourceDepsNode::tag_update(Depsgraph *graph)
}
}
-
-/* Root Node ============================================== */
-
-RootDepsNode::RootDepsNode() : scene(NULL), time_source(NULL)
-{
-}
-
-RootDepsNode::~RootDepsNode()
-{
- OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode);
-}
-
-TimeSourceDepsNode *RootDepsNode::add_time_source(const char *name)
-{
- if (!time_source) {
- DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
- time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", name);
- /*time_source->owner = this;*/ // XXX
- }
- return time_source;
-}
-
-DEG_DEPSNODE_DEFINE(RootDepsNode, DEPSNODE_TYPE_ROOT, "Root DepsNode");
-static DepsNodeFactoryImpl<RootDepsNode> DNTI_ROOT;
-
/* Time Source Node ======================================= */
-DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEPSNODE_TYPE_TIMESOURCE, "Time Source");
+DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEG_NODE_TYPE_TIMESOURCE, "Time Source");
static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
/* ID Node ================================================ */
@@ -158,8 +132,8 @@ static unsigned int id_deps_node_hash_key(const void *key_v)
{
const IDDepsNode::ComponentIDKey *key =
reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v);
- return hash_combine(BLI_ghashutil_uinthash(key->type),
- BLI_ghashutil_strhash_p(key->name));
+ return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(key->type),
+ BLI_ghashutil_strhash_p(key->name));
}
static bool id_deps_node_hash_key_cmp(const void *a, const void *b)
@@ -211,8 +185,9 @@ void IDDepsNode::init(const ID *id, const char *UNUSED(subdata))
/* Free 'id' node. */
IDDepsNode::~IDDepsNode()
{
- clear_components();
- BLI_ghash_free(components, id_deps_node_hash_key_free, NULL);
+ BLI_ghash_free(components,
+ id_deps_node_hash_key_free,
+ id_deps_node_hash_value_free);
}
ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
@@ -238,33 +213,13 @@ ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
return comp_node;
}
-void IDDepsNode::remove_component(eDepsNode_Type type, const char *name)
-{
- ComponentDepsNode *comp_node = find_component(type, name);
- if (comp_node) {
- /* Unregister. */
- ComponentIDKey key(type, name);
- BLI_ghash_remove(components,
- &key,
- id_deps_node_hash_key_free,
- id_deps_node_hash_value_free);
- }
-}
-
-void IDDepsNode::clear_components()
-{
- BLI_ghash_clear(components,
- id_deps_node_hash_key_free,
- id_deps_node_hash_value_free);
-}
-
void IDDepsNode::tag_update(Depsgraph *graph)
{
GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
{
/* TODO(sergey): What about drievrs? */
- bool do_component_tag = comp_node->type != DEPSNODE_TYPE_ANIMATION;
- if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ bool do_component_tag = comp_node->type != DEG_NODE_TYPE_ANIMATION;
+ if (comp_node->type == DEG_NODE_TYPE_ANIMATION) {
AnimData *adt = BKE_animdata_from_id(id);
/* Animation data might be null if relations are tagged for update. */
if (adt != NULL && (adt->recalc & ADT_RECALC_ANIM)) {
@@ -287,46 +242,13 @@ void IDDepsNode::finalize_build()
GHASH_FOREACH_END();
}
-DEG_DEPSNODE_DEFINE(IDDepsNode, DEPSNODE_TYPE_ID_REF, "ID Node");
+DEG_DEPSNODE_DEFINE(IDDepsNode, DEG_NODE_TYPE_ID_REF, "ID Node");
static DepsNodeFactoryImpl<IDDepsNode> DNTI_ID_REF;
-/* Subgraph Node ========================================== */
-
-/* Initialize 'subgraph' node - from pointer data given. */
-void SubgraphDepsNode::init(const ID *id, const char *UNUSED(subdata))
-{
- /* Store ID-ref if provided. */
- this->root_id = (ID *)id;
-
- /* NOTE: graph will need to be added manually,
- * as we don't have any way of passing this down.
- */
-}
-
-/* Free 'subgraph' node */
-SubgraphDepsNode::~SubgraphDepsNode()
-{
- /* Only free if graph not shared, of if this node is the first
- * reference to it...
- */
- // XXX: prune these flags a bit...
- if ((this->flag & SUBGRAPH_FLAG_FIRSTREF) || !(this->flag & SUBGRAPH_FLAG_SHARED)) {
- /* Free the referenced graph. */
- DEG_graph_free(reinterpret_cast< ::Depsgraph* >(graph));
- graph = NULL;
- }
-}
-
-DEG_DEPSNODE_DEFINE(SubgraphDepsNode, DEPSNODE_TYPE_SUBGRAPH, "Subgraph Node");
-static DepsNodeFactoryImpl<SubgraphDepsNode> DNTI_SUBGRAPH;
-
void deg_register_base_depsnodes()
{
- deg_register_node_typeinfo(&DNTI_ROOT);
deg_register_node_typeinfo(&DNTI_TIMESOURCE);
-
deg_register_node_typeinfo(&DNTI_ID_REF);
- deg_register_node_typeinfo(&DNTI_SUBGRAPH);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h
index 7c2f53840b6..9f1b61faf24 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node.h
@@ -127,22 +127,6 @@ struct TimeSourceDepsNode : public DepsNode {
DEG_DEPSNODE_DECLARE;
};
-/* Root Node. */
-struct RootDepsNode : public DepsNode {
- RootDepsNode();
- ~RootDepsNode();
-
- TimeSourceDepsNode *add_time_source(const char *name = "");
-
- /* scene that this corresponds to */
- Scene *scene;
-
- /* Entrypoint node for time-changed. */
- TimeSourceDepsNode *time_source;
-
- DEG_DEPSNODE_DECLARE;
-};
-
/* ID-Block Reference */
struct IDDepsNode : public DepsNode {
struct ComponentIDKey {
@@ -160,8 +144,6 @@ struct IDDepsNode : public DepsNode {
const char *name = "") const;
ComponentDepsNode *add_component(eDepsNode_Type type,
const char *name = "");
- void remove_component(eDepsNode_Type type, const char *name = "");
- void clear_components();
void tag_update(Depsgraph *graph);
@@ -185,41 +167,6 @@ struct IDDepsNode : public DepsNode {
DEG_DEPSNODE_DECLARE;
};
-/* Subgraph Reference. */
-struct SubgraphDepsNode : public DepsNode {
- void init(const ID *id, const char *subdata);
- ~SubgraphDepsNode();
-
- /* Instanced graph. */
- Depsgraph *graph;
-
- /* ID-block at root of subgraph (if applicable). */
- ID *root_id;
-
- /* Number of nodes which use/reference this subgraph - if just 1, it may be
- * possible to merge into main,
- */
- size_t num_users;
-
- /* (eSubgraphRef_Flag) assorted settings for subgraph node. */
- int flag;
-
- DEG_DEPSNODE_DECLARE;
-};
-
-/* Flags for subgraph node */
-typedef enum eSubgraphRef_Flag {
- /* Subgraph referenced is shared with another reference, so shouldn't
- * free on exit.
- */
- SUBGRAPH_FLAG_SHARED = (1 << 0),
-
- /* Node is first reference to subgraph, so it can be freed when we are
- * removed.
- */
- SUBGRAPH_FLAG_FIRSTREF = (1 << 1),
-} eSubgraphRef_Flag;
-
void deg_register_base_depsnodes();
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
index 06f91ac7fdc..e87c87813e3 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
@@ -33,9 +33,10 @@
#include <stdio.h>
#include <cstring> /* required for STREQ later on. */
-extern "C" {
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+extern "C" {
#include "DNA_object_types.h"
#include "BKE_action.h"
@@ -44,7 +45,6 @@ extern "C" {
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
-#include "util/deg_util_hash.h"
namespace DEG {
@@ -95,8 +95,8 @@ static unsigned int comp_node_hash_key(const void *key_v)
{
const ComponentDepsNode::OperationIDKey *key =
reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(key_v);
- return hash_combine(BLI_ghashutil_uinthash(key->opcode),
- BLI_ghashutil_strhash_p(key->name));
+ return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(key->opcode),
+ BLI_ghashutil_strhash_p(key->name));
}
static bool comp_node_hash_key_cmp(const void *a, const void *b)
@@ -198,32 +198,20 @@ OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode,
return has_operation(key);
}
-OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+OperationDepsNode *ComponentDepsNode::add_operation(const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
const char *name,
int name_tag)
{
OperationDepsNode *op_node = has_operation(opcode, name, name_tag);
if (!op_node) {
- DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_OPERATION);
+ DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_OPERATION);
op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name);
/* register opnode in this component's operation set */
OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name, name_tag);
BLI_ghash_insert(operations_map, key, op_node);
- /* set as entry/exit node of component (if appropriate) */
- if (optype == DEPSOP_TYPE_INIT) {
- BLI_assert(this->entry_operation == NULL);
- this->entry_operation = op_node;
- }
- else if (optype == DEPSOP_TYPE_POST) {
- // XXX: review whether DEPSOP_TYPE_OUT is better than DEPSOP_TYPE_POST, or maybe have both?
- BLI_assert(this->exit_operation == NULL);
- this->exit_operation = op_node;
- }
-
/* set backlink */
op_node->owner = this;
}
@@ -235,13 +223,24 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype,
/* attach extra data */
op_node->evaluate = op;
- op_node->optype = optype;
op_node->opcode = opcode;
op_node->name = name;
return op_node;
}
+void ComponentDepsNode::set_entry_operation(OperationDepsNode *op_node)
+{
+ BLI_assert(entry_operation == NULL);
+ entry_operation = op_node;
+}
+
+void ComponentDepsNode::set_exit_operation(OperationDepsNode *op_node)
+{
+ BLI_assert(exit_operation == NULL);
+ exit_operation = op_node;
+}
+
void ComponentDepsNode::clear_operations()
{
if (operations_map != NULL) {
@@ -336,37 +335,37 @@ void ComponentDepsNode::finalize_build()
/* Parameter Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEPSNODE_TYPE_PARAMETERS, "Parameters Component");
+DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEG_NODE_TYPE_PARAMETERS, "Parameters Component");
static DepsNodeFactoryImpl<ParametersComponentDepsNode> DNTI_PARAMETERS;
/* Animation Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(AnimationComponentDepsNode, DEPSNODE_TYPE_ANIMATION, "Animation Component");
+DEG_DEPSNODE_DEFINE(AnimationComponentDepsNode, DEG_NODE_TYPE_ANIMATION, "Animation Component");
static DepsNodeFactoryImpl<AnimationComponentDepsNode> DNTI_ANIMATION;
/* Transform Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(TransformComponentDepsNode, DEPSNODE_TYPE_TRANSFORM, "Transform Component");
+DEG_DEPSNODE_DEFINE(TransformComponentDepsNode, DEG_NODE_TYPE_TRANSFORM, "Transform Component");
static DepsNodeFactoryImpl<TransformComponentDepsNode> DNTI_TRANSFORM;
/* Proxy Component Defines ================================ */
-DEG_DEPSNODE_DEFINE(ProxyComponentDepsNode, DEPSNODE_TYPE_PROXY, "Proxy Component");
+DEG_DEPSNODE_DEFINE(ProxyComponentDepsNode, DEG_NODE_TYPE_PROXY, "Proxy Component");
static DepsNodeFactoryImpl<ProxyComponentDepsNode> DNTI_PROXY;
/* Geometry Component Defines ============================= */
-DEG_DEPSNODE_DEFINE(GeometryComponentDepsNode, DEPSNODE_TYPE_GEOMETRY, "Geometry Component");
+DEG_DEPSNODE_DEFINE(GeometryComponentDepsNode, DEG_NODE_TYPE_GEOMETRY, "Geometry Component");
static DepsNodeFactoryImpl<GeometryComponentDepsNode> DNTI_GEOMETRY;
/* Sequencer Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(SequencerComponentDepsNode, DEPSNODE_TYPE_SEQUENCER, "Sequencer Component");
+DEG_DEPSNODE_DEFINE(SequencerComponentDepsNode, DEG_NODE_TYPE_SEQUENCER, "Sequencer Component");
static DepsNodeFactoryImpl<SequencerComponentDepsNode> DNTI_SEQUENCER;
/* Pose Component ========================================= */
-DEG_DEPSNODE_DEFINE(PoseComponentDepsNode, DEPSNODE_TYPE_EVAL_POSE, "Pose Eval Component");
+DEG_DEPSNODE_DEFINE(PoseComponentDepsNode, DEG_NODE_TYPE_EVAL_POSE, "Pose Eval Component");
static DepsNodeFactoryImpl<PoseComponentDepsNode> DNTI_EVAL_POSE;
/* Bone Component ========================================= */
@@ -388,22 +387,22 @@ void BoneComponentDepsNode::init(const ID *id, const char *subdata)
this->pchan = BKE_pose_channel_find_name(ob->pose, subdata);
}
-DEG_DEPSNODE_DEFINE(BoneComponentDepsNode, DEPSNODE_TYPE_BONE, "Bone Component");
+DEG_DEPSNODE_DEFINE(BoneComponentDepsNode, DEG_NODE_TYPE_BONE, "Bone Component");
static DepsNodeFactoryImpl<BoneComponentDepsNode> DNTI_BONE;
/* Particles Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(ParticlesComponentDepsNode, DEPSNODE_TYPE_EVAL_PARTICLES, "Particles Component");
+DEG_DEPSNODE_DEFINE(ParticlesComponentDepsNode, DEG_NODE_TYPE_EVAL_PARTICLES, "Particles Component");
static DepsNodeFactoryImpl<ParticlesComponentDepsNode> DNTI_EVAL_PARTICLES;
/* Shading Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(ShadingComponentDepsNode, DEPSNODE_TYPE_SHADING, "Shading Component");
+DEG_DEPSNODE_DEFINE(ShadingComponentDepsNode, DEG_NODE_TYPE_SHADING, "Shading Component");
static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING;
/* Cache Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(CacheComponentDepsNode, DEPSNODE_TYPE_CACHE, "Cache Component");
+DEG_DEPSNODE_DEFINE(CacheComponentDepsNode, DEG_NODE_TYPE_CACHE, "Cache Component");
static DepsNodeFactoryImpl<CacheComponentDepsNode> DNTI_CACHE;
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h
index 969771a29c9..4ef7dad3ac6 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h
@@ -99,12 +99,18 @@ struct ComponentDepsNode : public DepsNode {
* \param op: The operation to perform
* \param name: Identifier for operation - used to find/locate it again
*/
- OperationDepsNode *add_operation(eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ OperationDepsNode *add_operation(const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
const char *name,
int name_tag);
+ /* Entry/exit operations management.
+ *
+ * Use those instead of direct set since this will perform sanity checks.
+ */
+ void set_entry_operation(OperationDepsNode *op_node);
+ void set_exit_operation(OperationDepsNode *op_node);
+
void clear_operations();
void tag_update(Depsgraph *graph);
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
index 9eed4dfe8d8..7467264f612 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
@@ -32,13 +32,11 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BLI_utildefines.h"
-} /* extern "C" */
+#include "BLI_ghash.h"
#include "intern/depsgraph.h"
#include "intern/depsgraph_intern.h"
-#include "util/deg_util_hash.h"
namespace DEG {
@@ -67,7 +65,7 @@ string OperationDepsNode::identifier() const
string OperationDepsNode::full_identifier() const
{
string owner_str = "";
- if (owner->type == DEPSNODE_TYPE_BONE) {
+ if (owner->type == DEG_NODE_TYPE_BONE) {
owner_str = string(owner->owner->name) + "." + owner->name;
}
else {
@@ -86,7 +84,19 @@ void OperationDepsNode::tag_update(Depsgraph *graph)
graph->add_entry_tag(this);
}
-DEG_DEPSNODE_DEFINE(OperationDepsNode, DEPSNODE_TYPE_OPERATION, "Operation");
+void OperationDepsNode::set_as_entry()
+{
+ BLI_assert(owner != NULL);
+ owner->set_entry_operation(this);
+}
+
+void OperationDepsNode::set_as_exit()
+{
+ BLI_assert(owner != NULL);
+ owner->set_exit_operation(this);
+}
+
+DEG_DEPSNODE_DEFINE(OperationDepsNode, DEG_NODE_TYPE_OPERATION, "Operation");
static DepsNodeFactoryImpl<OperationDepsNode> DNTI_OPERATION;
void deg_register_operation_depsnodes()
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
index 598393054db..1e5c3832d03 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
@@ -44,9 +44,6 @@ typedef enum eDepsOperation_Flag {
DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0),
/* node was directly modified, causing need for update */
- /* XXX: intention is to make it easier to tell when we just need to
- * take subgraphs.
- */
DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1),
/* Operation is evaluated using CPython; has GIL and security
@@ -57,8 +54,6 @@ typedef enum eDepsOperation_Flag {
/* Atomic Operation - Base type for all operations */
struct OperationDepsNode : public DepsNode {
-
-
OperationDepsNode();
~OperationDepsNode();
@@ -72,21 +67,21 @@ struct OperationDepsNode : public DepsNode {
OperationDepsNode *get_entry_operation() { return this; }
OperationDepsNode *get_exit_operation() { return this; }
+ /* Set this operation as compoonent's entry/exit operation. */
+ void set_as_entry();
+ void set_as_exit();
+
/* Component that contains the operation. */
ComponentDepsNode *owner;
/* Callback for operation. */
DepsEvalOperationCb evaluate;
-
/* How many inlinks are we still waiting on before we can be evaluated. */
uint32_t num_links_pending;
float eval_priority;
bool scheduled;
- /* Stage of evaluation */
- eDepsOperation_Type optype;
-
/* Identifier for the operation being performed. */
eDepsOperation_Code opcode;
diff --git a/source/blender/depsgraph/util/deg_util_foreach.h b/source/blender/depsgraph/util/deg_util_foreach.h
index 87d37168d51..cb7361fc708 100644
--- a/source/blender/depsgraph/util/deg_util_foreach.h
+++ b/source/blender/depsgraph/util/deg_util_foreach.h
@@ -46,28 +46,3 @@
# define foreach(x, y) for (x; false; (void)y)
#endif
-
-#define GHASH_FOREACH_BEGIN(type, var, what) \
- do { \
- GHashIterator gh_iter##var; \
- GHASH_ITER(gh_iter##var, what) { \
- type var = reinterpret_cast<type>(BLI_ghashIterator_getValue(&gh_iter##var)); \
-
-#define GHASH_FOREACH_END() \
- } \
- } while(0)
-
-#define GSET_FOREACH_BEGIN(type, var, what) \
- do { \
- GSetIterator gh_iter##var; \
- GSET_ITER(gh_iter##var, what) { \
- type var = reinterpret_cast<type>(BLI_gsetIterator_getKey(&gh_iter##var)); \
-
-#define GSET_FOREACH_END() \
- } \
- } while(0)
-
-#define LINKLIST_FOREACH(type, var, list) \
- for (type var = (type)((list)->first); \
- var != NULL; \
- var = (type)(((Link*)(var))->next))
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 57302c18a88..dba060bfb29 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -2775,7 +2775,7 @@ static bAnimChannelType ACF_DSMCLIP =
acf_generic_indention_1, /* indent level */
acf_generic_basic_offset, /* offset */
- acf_generic_idblock_name , /* name */
+ acf_generic_idblock_name, /* name */
acf_generic_idfill_name_prop, /* name prop */
acf_dsmclip_icon, /* icon */
@@ -3856,7 +3856,8 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
if (ac->sl) {
if ((ac->spacetype == SPACE_IPO) &&
(acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE) ||
- acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE))) {
+ acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)))
+ {
/* for F-Curves, draw color-preview of curve behind checkbox */
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = (FCurve *)ale->data;
@@ -4457,8 +4458,8 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
* a callback available (e.g. broken F-Curve rename)
*/
if (acf->name_prop(ale, &ptr, &prop)) {
- const short margin_x = 3 * iroundf(UI_DPI_FAC);
- const short channel_height = iroundf(ymaxc - yminc);
+ const short margin_x = 3 * round_fl_to_int(UI_DPI_FAC);
+ const short channel_height = round_fl_to_int(ymaxc - yminc);
const short width = ac->ar->winx - offset - (margin_x * 2);
uiBut *but;
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 437dd2b2de2..cc77a321a89 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -309,6 +309,28 @@ static void animchan_sync_fcurve(bAnimContext *ac, bAnimListElem *ale, FCurve **
}
}
+/* perform syncing updates for GPencil Layers */
+static void animchan_sync_gplayer(bAnimContext *UNUSED(ac), bAnimListElem *ale)
+{
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+
+ /* Make sure the selection flags agree with the "active" flag.
+ * The selection flags are used in the Dopesheet only, whereas
+ * the active flag is used everywhere else. Hence, we try to
+ * sync these here so that it all seems to be have as the user
+ * expects - T50184
+ *
+ * Assume that we only really do this when the active status changes.
+ * (NOTE: This may prove annoying if it means selection is always lost)
+ */
+ if (gpl->flag & GP_LAYER_ACTIVE) {
+ gpl->flag |= GP_LAYER_SELECT;
+ }
+ else {
+ gpl->flag &= ~GP_LAYER_SELECT;
+ }
+}
+
/* ---------------- */
/* Main call to be exported to animation editors */
@@ -343,6 +365,10 @@ void ANIM_sync_animchannels_to_data(const bContext *C)
case ANIMTYPE_FCURVE:
animchan_sync_fcurve(&ac, ale, &active_fcurve);
break;
+
+ case ANIMTYPE_GPLAYER:
+ animchan_sync_gplayer(&ac, ale);
+ break;
}
}
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 33e44d73894..a6febdb575e 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -46,6 +46,8 @@
#include "BLI_dlrbTree.h"
#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_nla.h"
#include "BKE_mask.h"
@@ -115,7 +117,8 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
/* Draw a light green line to indicate current frame */
UI_ThemeColor(TH_CFRAME);
- const float x = (float)(scene->r.cfra * scene->r.framelen);
+ const float time = scene->r.cfra + scene->r.subframe;
+ const float x = (float)(time * scene->r.framelen);
glLineWidth((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0);
@@ -308,7 +311,8 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
fcu->prev_norm_factor = 1.0f;
if (fcu->bezt) {
- BezTriple *bezt;
+ const bool use_preview_only = PRVRANGEON;
+ const BezTriple *bezt;
int i;
float max_coord = -FLT_MAX;
float min_coord = FLT_MAX;
@@ -318,28 +322,77 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
return 1.0f;
}
- if (PRVRANGEON) {
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (IN_RANGE_INCL(bezt->vec[1][0], scene->r.psfra, scene->r.pefra)) {
- max_coord = max_ff(max_coord, bezt->vec[0][1]);
- max_coord = max_ff(max_coord, bezt->vec[1][1]);
- max_coord = max_ff(max_coord, bezt->vec[2][1]);
-
- min_coord = min_ff(min_coord, bezt->vec[0][1]);
- min_coord = min_ff(min_coord, bezt->vec[1][1]);
- min_coord = min_ff(min_coord, bezt->vec[2][1]);
- }
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (use_preview_only && !IN_RANGE_INCL(bezt->vec[1][0],
+ scene->r.psfra,
+ scene->r.pefra))
+ {
+ continue;
}
- }
- else {
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- max_coord = max_ff(max_coord, bezt->vec[0][1]);
+
+ if (i == 0) {
+ /* We ignore extrapolation flags and handle here, and use the
+ * control point position only. so we normalize "interesting"
+ * part of the curve.
+ *
+ * Here we handle left extrapolation.
+ */
max_coord = max_ff(max_coord, bezt->vec[1][1]);
- max_coord = max_ff(max_coord, bezt->vec[2][1]);
- min_coord = min_ff(min_coord, bezt->vec[0][1]);
min_coord = min_ff(min_coord, bezt->vec[1][1]);
- min_coord = min_ff(min_coord, bezt->vec[2][1]);
+ }
+ else {
+ const BezTriple *prev_bezt = bezt - 1;
+ if (prev_bezt->ipo == BEZT_IPO_CONST) {
+ /* Constant interpolation: previous CV value is used up
+ * to the current keyframe.
+ */
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ }
+ else if (prev_bezt->ipo == BEZT_IPO_LIN) {
+ /* Linear interpolation: min/max using both previous and
+ * and current CV.
+ */
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
+ }
+ else if (prev_bezt->ipo == BEZT_IPO_BEZ) {
+ const int resol = fcu->driver
+ ? 32
+ : min_ii((int)(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])), 32);
+ if (resol < 2) {
+ max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
+ }
+ else {
+ float data[120];
+ float v1[2], v2[2], v3[2], v4[2];
+
+ v1[0] = prev_bezt->vec[1][0];
+ v1[1] = prev_bezt->vec[1][1];
+ v2[0] = prev_bezt->vec[2][0];
+ v2[1] = prev_bezt->vec[2][1];
+
+ v3[0] = bezt->vec[0][0];
+ v3[1] = bezt->vec[0][1];
+ v4[0] = bezt->vec[1][0];
+ v4[1] = bezt->vec[1][1];
+
+ correct_bezpart(v1, v2, v3, v4);
+
+ BKE_curve_forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float) * 3);
+ BKE_curve_forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float) * 3);
+
+ for (int j = 0; j <= resol; ++j) {
+ const float *fp = &data[j * 3];
+ max_coord = max_ff(max_coord, fp[1]);
+ min_coord = min_ff(min_coord, fp[1]);
+ }
+ }
+ }
}
}
@@ -526,6 +579,7 @@ void ANIM_center_frame(struct bContext *C, int smooth_viewtx)
break;
}
/* else drop through, keep range instead */
+ ATTR_FALLTHROUGH;
case ZOOM_FRAME_MODE_KEEP_RANGE:
default:
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index c12a050e9ba..e18560b95af 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -2223,7 +2223,7 @@ typedef struct tAnimFilterModifiersContext {
/* dependency walker callback for modifier dependencies */
-static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, int UNUSED(cd_flag))
+static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, int UNUSED(cb_flag))
{
tAnimFilterModifiersContext *afm = (tAnimFilterModifiersContext *)afm_ptr;
ID *owner_id = &ob->id;
@@ -2247,6 +2247,8 @@ static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin
}
/* TODO: images? */
+ default:
+ break;
}
}
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 823cde75334..efcc3e9477c 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -149,7 +149,7 @@ int ED_markers_post_apply_transform(ListBase *markers, Scene *scene, int mode, f
(side == 'L' && marker->frame < cfra) ||
(side == 'R' && marker->frame >= cfra))
{
- marker->frame += iroundf(value);
+ marker->frame += round_fl_to_int(value);
changed_tot++;
}
break;
@@ -157,7 +157,7 @@ int ED_markers_post_apply_transform(ListBase *markers, Scene *scene, int mode, f
case TFM_TIME_SCALE:
{
/* rescale the distance between the marker and the current frame */
- marker->frame = cfra + iroundf((float)(marker->frame - cfra) * value);
+ marker->frame = cfra + round_fl_to_int((float)(marker->frame - cfra) * value);
changed_tot++;
break;
}
@@ -195,7 +195,7 @@ TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x)
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
{
TimeMarker *nearest = ED_markers_find_nearest_marker(markers, x);
- return (nearest) ? (nearest->frame) : iroundf(x);
+ return (nearest) ? (nearest->frame) : round_fl_to_int(x);
}
@@ -888,13 +888,14 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *even
ed_marker_move_cancel(C, op);
return OPERATOR_CANCELLED;
}
- /* else continue; <--- see if release event should be caught for tweak-end */
+ /* else continue; <--- see if release event should be caught for tweak-end */
+ ATTR_FALLTHROUGH;
case RETKEY:
case PADENTER:
case LEFTMOUSE:
case MIDDLEMOUSE:
- if (WM_modal_tweak_exit(event, mm->event_type)) {
+ if (WM_event_is_modal_tweak_exit(event, mm->event_type)) {
ed_marker_move_exit(C, op);
WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index c0d6963acbb..fcdd45d4ac3 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -95,7 +95,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- int frame = RNA_int_get(op->ptr, "frame");
+ float frame = RNA_float_get(op->ptr, "frame");
bool do_snap = RNA_boolean_get(op->ptr, "snap");
if (do_snap && CTX_wm_space_seq(C)) {
@@ -103,10 +103,16 @@ static void change_frame_apply(bContext *C, wmOperator *op)
}
/* set the new frame number */
- CFRA = frame;
+ if (scene->r.flag & SCER_SHOW_SUBFRAME) {
+ CFRA = (int)frame;
+ SUBFRA = frame - (int)frame;
+ }
+ else {
+ CFRA = round_fl_to_int(frame);
+ SUBFRA = 0.0f;
+ }
FRAMENUMBER_MIN_CLAMP(CFRA);
- SUBFRA = 0.0f;
-
+
/* do updates */
BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -125,19 +131,16 @@ static int change_frame_exec(bContext *C, wmOperator *op)
/* ---- */
/* Get frame from mouse coordinates */
-static int frame_from_event(bContext *C, const wmEvent *event)
+static float frame_from_event(bContext *C, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
- float viewx;
- int frame;
+ float frame;
/* convert from region coordinates to View2D 'tot' space */
- viewx = UI_view2d_region_to_view_x(&region->v2d, event->mval[0]);
-
- /* round result to nearest int (frames are ints!) */
- frame = iroundf(viewx);
+ frame = UI_view2d_region_to_view_x(&region->v2d, event->mval[0]);
+ /* respect preview range restrictions (if only allowed to move around within that range) */
if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) {
CLAMP(frame, PSFRA, PEFRA);
}
@@ -187,7 +190,7 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
* as user could click on a single frame (jump to frame) as well as
* click-dragging over a range (modal scrubbing).
*/
- RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
+ RNA_float_set(op->ptr, "frame", frame_from_event(C, event));
change_frame_seq_preview_begin(C, event);
@@ -215,7 +218,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
case MOUSEMOVE:
- RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
+ RNA_float_set(op->ptr, "frame", frame_from_event(C, event));
change_frame_apply(C, op);
break;
@@ -268,7 +271,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
ot->undo_group = "FRAME_CHANGE";
/* rna */
- ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
+ ot->prop = RNA_def_float(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
prop = RNA_def_boolean(ot->srna, "snap", false, "Snap", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -298,8 +301,8 @@ static int previewrange_define_exec(bContext *C, wmOperator *op)
if (efra < sfra) efra = sfra;
scene->r.flag |= SCER_PRV_RANGE;
- scene->r.psfra = iroundf(sfra);
- scene->r.pefra = iroundf(efra);
+ scene->r.psfra = round_fl_to_int(sfra);
+ scene->r.pefra = round_fl_to_int(efra);
/* send notifiers */
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 21c25f829b1..52b93edae15 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -40,6 +40,7 @@
#include "BLI_string.h"
#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
#include "DNA_texture_types.h"
#include "BKE_animsys.h"
@@ -1029,6 +1030,11 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op)
UI_context_update_anim_flag(C);
+ DAG_relations_tag_update(CTX_data_main(C));
+ DAG_id_tag_update(ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); // XXX
+
MEM_freeN(path);
}
}
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 4571df0f077..9d25fc9e1a3 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -452,7 +452,7 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac)
ok |= KEYFRAME_OK_H2; \
} \
} (void)0
-
+
/* ------------------------ */
static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt)
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 1703210f0b6..071c5fab9d7 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -37,6 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
@@ -51,6 +52,7 @@
#include "BKE_deform.h"
#include "RNA_access.h"
+#include "RNA_enum_types.h"
#include "ED_anim_api.h"
#include "ED_keyframing.h"
@@ -668,7 +670,7 @@ static void flip_names(tAnimCopybufItem *aci, char **name)
/* more ninja stuff, temporary substitute with NULL terminator */
str_start[length] = 0;
- BKE_deform_flip_side_name(bname_new, str_start, false);
+ BLI_string_flip_side_name(bname_new, str_start, false, sizeof(bname_new));
str_start[length] = '\"';
str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path");
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index f2a35bb1553..540886196fe 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -1073,10 +1073,11 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
/* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor,
* is determined by the array index for the F-Curve
*/
- if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
+ PropertySubType prop_subtype = RNA_property_subtype(prop);
+ if (ELEM(prop_subtype, 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) {
+ else if (ELEM(prop_subtype, PROP_QUATERNION)) {
fcu->color_mode = FCURVE_COLOR_AUTO_YRGB;
}
}
@@ -1785,7 +1786,9 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
NlaStrip *strip = (NlaStrip *)ptr.data;
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
- success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0);
+ if (fcu) {
+ success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0);
+ }
}
else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) {
/* Driven property - Find driver */
@@ -1890,27 +1893,27 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
NlaStrip *strip = (NlaStrip *)ptr.data;
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0);
- BLI_assert(fcu != NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */
-
- if (BKE_fcurve_is_protected(fcu)) {
- BKE_reportf(op->reports, RPT_WARNING,
- "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
- strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2);
- }
- else {
- /* remove the keyframe directly
- * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve,
- * and delete_keyframe() expects the FCurve to be part of an action
- */
- bool found = false;
- int i;
-
- /* try to find index of beztriple to get rid of */
- i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
- if (found) {
- /* delete the key at the index (will sanity check + do recalc afterwards) */
- delete_fcurve_key(fcu, i, 1);
- success = true;
+ if (fcu) {
+ if (BKE_fcurve_is_protected(fcu)) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
+ strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2);
+ }
+ else {
+ /* remove the keyframe directly
+ * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve,
+ * and delete_keyframe() expects the FCurve to be part of an action
+ */
+ bool found = false;
+ int i;
+
+ /* try to find index of beztriple to get rid of */
+ i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
+ if (found) {
+ /* delete the key at the index (will sanity check + do recalc afterwards) */
+ delete_fcurve_key(fcu, i, 1);
+ success = true;
+ }
}
}
}
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index 4408ec26b3f..0a27fe14de7 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -1052,6 +1052,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
break;
}
+ default:
+ break;
}
/* send notifiers for updates (this doesn't require context to work!) */
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 559d93c7eb1..bbc81f522fa 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_ghash.h"
+#include "BLI_string_utils.h"
#include "BKE_action.h"
#include "BKE_constraint.h"
@@ -231,7 +232,7 @@ static int armature_click_extrude_invoke(bContext *C, wmOperator *op, const wmEv
copy_v3_v3(oldcurs, fp);
VECCOPY2D(mval_f, event->mval);
- ED_view3d_win_to_3d(ar, fp, mval_f, tvec);
+ ED_view3d_win_to_3d(v3d, ar, fp, mval_f, tvec);
copy_v3_v3(fp, tvec);
/* extrude to the where new cursor is and store the operation result */
@@ -619,9 +620,9 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
if (EBONE_VISIBLE(arm, ebone_iter) &&
(ebone_iter->flag & BONE_SELECTED))
{
- char name_flip[MAX_VGROUP_NAME];
+ char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+ BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
if (STREQ(name_flip, ebone_iter->name)) {
/* if the name matches, we don't have the potential to be mirrored, just skip */
@@ -679,9 +680,9 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
/* will be set if the mirror bone already exists (no need to make a new one) */
(ebone_iter->temp.ebone == NULL))
{
- char name_flip[MAX_VGROUP_NAME];
+ char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+ BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
/* bones must have a side-suffix */
if (!STREQ(name_flip, ebone_iter->name)) {
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 47e73f9b777..51b76563c72 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -66,7 +66,7 @@
/* ************************** Object Tools Exports ******************************* */
/* NOTE: these functions are exported to the Object module to be called from the tools there */
-void ED_armature_apply_transform(Object *ob, float mat[4][4])
+void ED_armature_apply_transform(Object *ob, float mat[4][4], const bool do_props)
{
bArmature *arm = ob->data;
@@ -74,14 +74,14 @@ void ED_armature_apply_transform(Object *ob, float mat[4][4])
ED_armature_to_edit(arm);
/* Transform the bones */
- ED_armature_transform_bones(arm, mat);
+ ED_armature_transform_bones(arm, mat, do_props);
/* Turn the list into an armature */
ED_armature_from_edit(arm);
ED_armature_edit_free(arm);
}
-void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4])
+void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props)
{
EditBone *ebone;
float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */
@@ -106,27 +106,29 @@ void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4])
/* apply the transformed roll back */
mat3_to_vec_roll(tmat, NULL, &ebone->roll);
- ebone->rad_head *= scale;
- ebone->rad_tail *= scale;
- ebone->dist *= scale;
-
- /* we could be smarter and scale by the matrix along the x & z axis */
- ebone->xwidth *= scale;
- ebone->zwidth *= scale;
+ if (do_props) {
+ ebone->rad_head *= scale;
+ ebone->rad_tail *= scale;
+ ebone->dist *= scale;
+
+ /* we could be smarter and scale by the matrix along the x & z axis */
+ ebone->xwidth *= scale;
+ ebone->zwidth *= scale;
+ }
}
}
-void ED_armature_transform(struct bArmature *arm, float mat[4][4])
+void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props)
{
if (arm->edbo) {
- ED_armature_transform_bones(arm, mat);
+ ED_armature_transform_bones(arm, mat, do_props);
}
else {
/* Put the armature into editmode */
ED_armature_to_edit(arm);
/* Transform the bones */
- ED_armature_transform_bones(arm, mat);
+ ED_armature_transform_bones(arm, mat, do_props);
/* Go back to object mode*/
ED_armature_from_edit(arm);
@@ -220,7 +222,7 @@ float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const bool
vec_roll_to_mat3_normalized(nor, 0.0f, mat);
/* project the new_up_axis along the normal */
- project_v3_v3v3(vec, align_axis, nor);
+ project_v3_v3v3_normalized(vec, align_axis, nor);
sub_v3_v3v3(align_axis_proj, align_axis, vec);
if (axis_only) {
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index b39b4bd81ee..190b0610059 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -247,8 +247,10 @@ void armature_select_mirrored_ex(struct bArmature *arm, const int flag);
void armature_select_mirrored(struct bArmature *arm);
void armature_tag_unselect(struct bArmature *arm);
-void *get_nearest_bone(struct bContext *C, short findunsel, int x, int y);
-void *get_bone_from_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer, short hits, short findunsel, bool do_nearest);
+void *get_nearest_bone(struct bContext *C, const int xy[2], bool findunsel);
+void *get_bone_from_selectbuffer(
+ struct Scene *scene, struct Base *base, const unsigned int *buffer, short hits,
+ bool findunsel, bool do_nearest);
int bone_looper(struct Object *ob, struct Bone *bone, void *data,
int (*bone_func)(struct Object *, struct Bone *, void *));
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 56dbdb3a639..db4b642fe91 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -37,6 +37,8 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -297,6 +299,55 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
}
}
+typedef struct BoneFlipNameData {
+ struct BoneFlipNameData *next, *prev;
+ char *name;
+ char name_flip[MAXBONENAME];
+} BoneFlipNameData;
+
+/**
+ * Renames (by flipping) all selected bones at once.
+ *
+ * This way if we are flipping related bones (e.g., Bone.L, Bone.R) at the same time
+ * all the bones are safely renamed, without conflicting with each other.
+ *
+ * \param arm: Armature the bones belong to
+ * \param bones_names: List of BoneConflict elems.
+ */
+void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names)
+{
+ ListBase bones_names_conflicts = {NULL};
+ BoneFlipNameData *bfn;
+
+ /* First pass: generate flip names, and blindly rename.
+ * If rename did not yield expected result, store both bone's name and expected flipped one into temp list
+ * for second pass. */
+ for (LinkData *link = bones_names->first; link; link = link->next) {
+ char name_flip[MAXBONENAME];
+ char *name = link->data;
+
+ /* Do not strip numbers, otherwise we'll end up with completely mismatched names in cases like
+ * Bone.R, Bone.R.001, Bone.R.002, etc. */
+ BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
+
+ ED_armature_bone_rename(arm, name, name_flip);
+
+ if (!STREQ(name, name_flip)) {
+ bfn = alloca(sizeof(BoneFlipNameData));
+ bfn->name = name;
+ BLI_strncpy(bfn->name_flip, name_flip, sizeof(bfn->name_flip));
+ BLI_addtail(&bones_names_conflicts, bfn);
+ }
+ }
+
+ /* Second pass to handle the bones that have naming conflicts with other bones.
+ * Note that if the other bone was not selected, its name was not flipped, so conflict remains and that second
+ * rename simply generates a new numbered alternative name. */
+ for (bfn = bones_names_conflicts.first; bfn; bfn = bfn->next) {
+ ED_armature_bone_rename(arm, bfn->name, bfn->name_flip);
+ }
+}
+
/* ************************************************** */
/* Bone Renaming - EditMode */
@@ -304,20 +355,24 @@ static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_edit_object(C);
bArmature *arm;
-
+
/* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
+ if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
+
arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
+
+ ListBase bones_names = {NULL};
+
CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
{
- char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, ebone->name, true);
- ED_armature_bone_rename(arm, ebone->name, name_flip);
+ BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name));
}
CTX_DATA_END;
+
+ ED_armature_bones_flip_names(arm, &bones_names);
+
+ BLI_freelistN(&bones_names);
/* since we renamed stuff... */
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 1c342657eec..417d7c8ba3b 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -380,7 +380,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
if (base->object->adt) {
if (ob->adt == NULL) {
/* no animdata, so just use a copy of the whole thing */
- ob->adt = BKE_animdata_copy(base->object->adt, false);
+ ob->adt = BKE_animdata_copy(bmain, base->object->adt, false);
}
else {
/* merge in data - we'll fix the drivers manually */
@@ -391,7 +391,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
if (curarm->adt) {
if (arm->adt == NULL) {
/* no animdata, so just use a copy of the whole thing */
- arm->adt = BKE_animdata_copy(curarm->adt, false);
+ arm->adt = BKE_animdata_copy(bmain, curarm->adt, false);
}
else {
/* merge in data - we'll fix the drivers manually */
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 5a70a45fad4..ed44214591c 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -35,9 +35,10 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BKE_context.h"
-#include "BKE_deform.h"
+//#include "BKE_deform.h"
#include "BKE_report.h"
#include "BIF_gl.h"
@@ -73,7 +74,9 @@ Bone *get_indexed_bone(Object *ob, int index)
/* See if there are any selected bones in this buffer */
/* only bones from base are checked on */
-void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, short findunsel, bool do_nearest)
+void *get_bone_from_selectbuffer(
+ Scene *scene, Base *base, const unsigned int *buffer, short hits,
+ bool findunsel, bool do_nearest)
{
Object *obedit = scene->obedit; // XXX get from context
Bone *bone;
@@ -102,8 +105,8 @@ void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer,
sel = (bone->flag & BONE_SELECTED);
else
sel = !(bone->flag & BONE_SELECTED);
-
- data = bone;
+
+ data = bone;
}
else {
data = NULL;
@@ -161,7 +164,7 @@ void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer,
/* used by posemode as well editmode */
/* only checks scene->basact! */
/* x and y are mouse coords (area space) */
-void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
+void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
{
ViewContext vc;
rcti rect;
@@ -171,10 +174,10 @@ void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
view3d_set_viewcontext(C, &vc);
// rect.xmin = ... mouseco!
- rect.xmin = rect.xmax = x;
- rect.ymin = rect.ymax = y;
+ rect.xmin = rect.xmax = xy[0];
+ rect.ymin = rect.ymax = xy[1];
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
if (hits > 0)
return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel, true);
@@ -196,10 +199,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
view3d_operator_needs_opengl(C);
- if (extend)
- bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
- else
- bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
+ bone = get_nearest_bone(C, event->mval, !extend);
if (!bone)
return OPERATOR_CANCELLED;
@@ -275,10 +275,24 @@ void ARMATURE_OT_select_linked(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
}
+/* utility function for get_nearest_editbonepoint */
+static int selectbuffer_ret_hits_12(unsigned int *UNUSED(buffer), const int hits12)
+{
+ return hits12;
+}
+
+static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const int hits5)
+{
+ const int offs = 4 * hits12;
+ memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
+ return hits5;
+}
+
/* does bones and points */
/* note that BONE ROOT only gets drawn for root bones (or without IK) */
-static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
- ListBase *edbo, int findunsel, int *selmask)
+static EditBone *get_nearest_editbonepoint(
+ ViewContext *vc, const int mval[2],
+ ListBase *edbo, bool findunsel, bool use_cycle, int *r_selmask)
{
bArmature *arm = (bArmature *)vc->obedit->data;
EditBone *ebone_next_act = arm->act_edbone;
@@ -288,7 +302,9 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
unsigned int buffer[MAXPICKBUF];
unsigned int hitresult, besthitresult = BONESEL_NOSEL;
int i, mindep = 5;
- short hits;
+ int hits12, hits5 = 0;
+
+ static int last_mval[2] = {-100, -100};
/* find the bone after the current active bone, so as to bump up its chances in selection.
* this way overlapping bones will cycle selection state as with objects. */
@@ -302,22 +318,59 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
ebone_next_act = NULL;
}
- rect.xmin = mval[0] - 5;
- rect.xmax = mval[0] + 5;
- rect.ymin = mval[1] - 5;
- rect.ymax = mval[1] + 5;
-
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true);
- if (hits == 0) {
- rect.xmin = mval[0] - 12;
- rect.xmax = mval[0] + 12;
- rect.ymin = mval[1] - 12;
- rect.ymax = mval[1] + 12;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true);
+ bool do_nearest = false;
+
+ /* define if we use solid nearest select or not */
+ if (use_cycle) {
+ if (vc->v3d->drawtype > OB_WIRE) {
+ do_nearest = true;
+ if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
+ do_nearest = false;
+ }
+ }
+ copy_v2_v2_int(last_mval, mval);
+ }
+ else {
+ if (vc->v3d->drawtype > OB_WIRE) {
+ do_nearest = true;
+ }
}
+
+ /* matching logic from 'mixed_bones_object_selectbuffer' */
+ const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
+ int hits = 0;
+
+ /* we _must_ end cache before return, use 'goto cache_end' */
+ view3d_opengl_select_cache_begin();
+
+ BLI_rcti_init_pt_radius(&rect, mval, 12);
+ hits12 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
+ if (hits12 == 1) {
+ hits = selectbuffer_ret_hits_12(buffer, hits12);
+ goto cache_end;
+ }
+ else if (hits12 > 0) {
+ int offs;
+
+ offs = 4 * hits12;
+ BLI_rcti_init_pt_radius(&rect, mval, 5);
+ hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
+
+ if (hits5 == 1) {
+ hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
+ goto cache_end;
+ }
+
+ if (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); goto cache_end; }
+ else { hits = selectbuffer_ret_hits_12(buffer, hits12); goto cache_end; }
+ }
+
+cache_end:
+ view3d_opengl_select_cache_end();
+
/* See if there are any selected bones in this group */
if (hits > 0) {
-
+
if (hits == 1) {
if (!(buffer[3] & BONESEL_NOSEL))
besthitresult = buffer[3];
@@ -374,17 +427,17 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
ebone = BLI_findlink(edbo, besthitresult & ~BONESEL_ANY);
- *selmask = 0;
+ *r_selmask = 0;
if (besthitresult & BONESEL_ROOT)
- *selmask |= BONE_ROOTSEL;
+ *r_selmask |= BONE_ROOTSEL;
if (besthitresult & BONESEL_TIP)
- *selmask |= BONE_TIPSEL;
+ *r_selmask |= BONE_TIPSEL;
if (besthitresult & BONESEL_BONE)
- *selmask |= BONE_SELECTED;
+ *r_selmask |= BONE_SELECTED;
return ebone;
}
}
- *selmask = 0;
+ *r_selmask = 0;
return NULL;
}
@@ -438,8 +491,8 @@ bool ED_armature_select_pick(bContext *C, const int mval[2], bool extend, bool d
if (BIF_sk_selectStroke(C, mval, extend)) {
return true;
}
-
- nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask);
+
+ nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, true, true, &selmask);
if (nearBone) {
if (!extend && !deselect && !toggle) {
@@ -817,10 +870,10 @@ static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
{
EditBone *ebone;
- char body_tmp[MAX_VGROUP_NAME];
- char prefix_act[MAX_VGROUP_NAME];
+ char body_tmp[MAXBONENAME];
+ char prefix_act[MAXBONENAME];
- BKE_deform_split_prefix(ebone_act->name, prefix_act, body_tmp);
+ BLI_string_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name));
if (prefix_act[0] == '\0')
return;
@@ -828,8 +881,8 @@ static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
/* Find matches */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (EBONE_SELECTABLE(arm, ebone)) {
- char prefix_other[MAX_VGROUP_NAME];
- BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp);
+ char prefix_other[MAXBONENAME];
+ BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name));
if (STREQ(prefix_act, prefix_other)) {
ED_armature_ebone_select_set(ebone, true);
}
@@ -841,10 +894,10 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
{
EditBone *ebone;
- char body_tmp[MAX_VGROUP_NAME];
- char suffix_act[MAX_VGROUP_NAME];
+ char body_tmp[MAXBONENAME];
+ char suffix_act[MAXBONENAME];
- BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act);
+ BLI_string_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name));
if (suffix_act[0] == '\0')
return;
@@ -852,8 +905,8 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
/* Find matches */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (EBONE_SELECTABLE(arm, ebone)) {
- char suffix_other[MAX_VGROUP_NAME];
- BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other);
+ char suffix_other[MAXBONENAME];
+ BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name));
if (STREQ(suffix_act, suffix_other)) {
ED_armature_ebone_select_set(ebone, true);
}
@@ -1201,7 +1254,7 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const
view3d_operator_needs_opengl(C);
ebone_src = arm->act_edbone;
- ebone_dst = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
+ ebone_dst = get_nearest_bone(C, event->mval, false);
/* fallback to object selection */
if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 28fddbab796..e8d41f722d7 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -360,7 +361,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
if (dgroup && mirror) {
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, dgroup->name, false);
+ BLI_string_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip));
dgroupflip[j] = defgroup_find_name(ob, name_flip);
}
}
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 6979a324b69..a3b439536b7 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -34,6 +34,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BKE_armature.h"
#include "BKE_context.h"
@@ -262,7 +263,7 @@ EditBone *ED_armature_bone_get_mirrored(const ListBase *edbo, EditBone *ebo)
if (ebo == NULL)
return NULL;
- BKE_deform_flip_side_name(name_flip, ebo->name, false);
+ BLI_string_flip_side_name(name_flip, ebo->name, false, sizeof(name_flip));
if (!STREQ(name_flip, ebo->name)) {
return ED_armature_bone_find_name(edbo, name_flip);
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index cc4c1809fbc..bba486bc65c 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -970,6 +970,9 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
ToolSettings *ts = CTX_data_tool_settings(C);
int point_added = 0;
+ /* TODO: Since the function `ED_transform_snap_object_context_create_view3d` creates a cache,
+ * the ideal would be to call this function only at the beginning of the snap operation,
+ * or at the beginning of the operator itself */
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
CTX_data_main(C), CTX_data_scene(C), 0,
CTX_wm_region(C), CTX_wm_view3d(C));
@@ -1038,6 +1041,8 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
}
}
+ /* TODO: The ideal would be to call this function only once.
+ * At the end of the operator */
ED_transform_snap_object_context_destroy(snap_context);
return point_added;
}
@@ -1902,12 +1907,9 @@ static bool sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], c
view3d_set_viewcontext(C, &vc);
- rect.xmin = mval[0] - 5;
- rect.xmax = mval[0] + 5;
- rect.ymin = mval[1] - 5;
- rect.ymax = mval[1] + 5;
+ BLI_rcti_init_pt_radius(&rect, mval, 5);
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
if (hits > 0) {
int besthitresult = -1;
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 322476dcca0..86b7271bfff 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -593,20 +593,24 @@ static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm;
-
+
/* paranoia checks */
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
+
arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
+
+ ListBase bones_names = {NULL};
+
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
{
- char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, pchan->name, true);
- ED_armature_bone_rename(arm, pchan->name, name_flip);
+ BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name));
}
CTX_DATA_END;
+
+ ED_armature_bones_flip_names(arm, &bones_names);
+
+ BLI_freelistN(&bones_names);
/* since we renamed stuff... */
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 9309592bb46..25f1b282f14 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -34,6 +34,7 @@
#include "BLI_blenlib.h"
#include "BLI_dlrbTree.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -327,7 +328,7 @@ static int poselib_sanitize_exec(bContext *C, wmOperator *op)
/* add pose to poselib */
marker = MEM_callocN(sizeof(TimeMarker), "ActionMarker");
- BLI_strncpy(marker->name, "Pose", sizeof(marker->name));
+ BLI_snprintf(marker->name, sizeof(marker->name), "F%d Pose", (int)ak->cfra);
marker->frame = (int)ak->cfra;
marker->flag = -1;
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 44470c1f827..6e328552411 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -132,8 +132,9 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
/* called from editview.c, for mode-less pose selection */
/* assumes scene obact and basact is still on old situation */
-int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits,
- bool extend, bool deselect, bool toggle, bool do_nearest)
+bool ED_do_pose_selectbuffer(
+ Scene *scene, Base *base, const unsigned int *buffer, short hits,
+ bool extend, bool deselect, bool toggle, bool do_nearest)
{
Object *ob = base->object;
Bone *nearBone;
@@ -280,12 +281,9 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
const bool extend = RNA_boolean_get(op->ptr, "extend");
view3d_operator_needs_opengl(C);
-
- if (extend)
- bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
- else
- bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
-
+
+ bone = get_nearest_bone(C, event->mval, !extend);
+
if (!bone)
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 8e8345d34c9..f62073d56ef 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -39,6 +39,7 @@
#include "DNA_scene_types.h"
#include "BKE_fcurve.h"
+#include "BKE_nla.h"
#include "BKE_context.h"
#include "BKE_object.h"
@@ -94,12 +95,19 @@ typedef struct tPoseSlideOp {
ListBase pfLinks; /* links between posechannels and f-curves */
DLRBT_Tree keys; /* binary tree for quicker searching for keyframes (when applicable) */
- int cframe; /* current frame number */
- int prevFrame; /* frame before current frame (blend-from) */
- int nextFrame; /* frame after current frame (blend-to) */
+ int cframe; /* current frame number - global time */
- int mode; /* sliding mode (ePoseSlide_Modes) */
- int flag; /* unused for now, but can later get used for storing runtime settings.... */
+ int prevFrame; /* frame before current frame (blend-from) - global time */
+ int nextFrame; /* frame after current frame (blend-to) - global time */
+
+ float prevFrameF; /* prevFrame, but in local action time (for F-Curve lookups to work) */
+ float nextFrameF; /* nextFrame, but in local action time (for F-Curve lookups to work) */
+
+ short mode; /* sliding mode (ePoseSlide_Modes) */
+ short flag; /* unused for now, but can later get used for storing runtime settings.... */
+
+ short channels; /* which transforms/channels are affected (ePoseSlide_Channels) */
+ short axislock; /* axis-limits for transforms (ePoseSlide_AxisLock) */
float percentage; /* 0-1 value for determining the influence of whatever is relevant */
@@ -113,6 +121,49 @@ typedef enum ePoseSlide_Modes {
POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */
} ePoseSlide_Modes;
+
+/* Transforms/Channels to Affect */
+typedef enum ePoseSlide_Channels {
+ PS_TFM_ALL = 0, /* All transforms and properties */
+
+ PS_TFM_LOC, /* Loc/Rot/Scale */
+ PS_TFM_ROT,
+ PS_TFM_SIZE,
+
+ PS_TFM_BBONE_SHAPE, /* Bendy Bones */
+
+ PS_TFM_PROPS /* Custom Properties */
+} ePoseSlide_Channels;
+
+/* Property enum for ePoseSlide_Channels */
+static EnumPropertyItem prop_channels_types[] = {
+ {PS_TFM_ALL, "ALL", 0, "All Properties",
+ "All properties, including transforms, bendy bone shape, and custom properties"},
+ {PS_TFM_LOC, "LOC", 0, "Location", "Location only"},
+ {PS_TFM_ROT, "ROT", 0, "Rotation", "Rotation only"},
+ {PS_TFM_SIZE, "SIZE", 0, "Scale", "Scale only"},
+ {PS_TFM_BBONE_SHAPE, "BBONE", 0, "Bendy Bone", "Bendy Bone shape properties"},
+ {PS_TFM_PROPS, "CUSTOM", 0, "Custom Properties", "Custom properties"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* Axis Locks */
+typedef enum ePoseSlide_AxisLock {
+ PS_LOCK_X = (1 << 0),
+ PS_LOCK_Y = (1 << 1),
+ PS_LOCK_Z = (1 << 2)
+} ePoseSlide_AxisLock;
+
+/* Property enum for ePoseSlide_AxisLock */
+static EnumPropertyItem prop_axis_lock_types[] = {
+ {0, "FREE", 0, "Free", "All axes are affected"},
+ {PS_LOCK_X, "X", 0, "X", "Only X-axis transforms are affected"},
+ {PS_LOCK_Y, "Y", 0, "Y", "Only Y-axis transforms are affected"},
+ {PS_LOCK_Z, "Z", 0, "Z", "Only Z-axis transforms are affected"},
+ /* TODO: Combinations? */
+ {0, NULL, 0, NULL, NULL}
+};
+
/* ------------------------------------ */
/* operator init */
@@ -139,11 +190,19 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode)
pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
- /* check the settings from the context */
+ /* get the set of properties/axes that can be operated on */
+ pso->channels = RNA_enum_get(op->ptr, "channels");
+ pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
+
+ /* ensure validity of the settings from the context */
if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action))
return 0;
- else
- act = pso->ob->adt->action;
+
+ act = pso->ob->adt->action;
+
+ /* apply NLA mapping corrections so the frame lookups work */
+ pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
+ pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
/* for each Pose-Channel which gets affected, get the F-Curves for that channel
* and set the relevant transform flags...
@@ -209,9 +268,9 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
/* get keyframe values for endpoint poses to blend with */
/* previous/start */
- sVal = evaluate_fcurve(fcu, (float)pso->prevFrame);
+ sVal = evaluate_fcurve(fcu, pso->prevFrameF);
/* next/end */
- eVal = evaluate_fcurve(fcu, (float)pso->nextFrame);
+ eVal = evaluate_fcurve(fcu, pso->nextFrameF);
/* if both values are equal, don't do anything */
if (IS_EQF(sVal, eVal)) {
@@ -293,10 +352,20 @@ static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, floa
/* using this path, find each matching F-Curve for the variables we're interested in */
while ( (ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path)) ) {
FCurve *fcu = (FCurve *)ld->data;
-
- /* just work on these channels one by one... there's no interaction between values */
+ const int idx = fcu->array_index;
+ const int lock = pso->axislock;
+
+ /* check if this F-Curve is ok given the current axis locks */
BLI_assert(fcu->array_index < 3);
- pose_slide_apply_val(pso, fcu, &vec[fcu->array_index]);
+
+ if ((lock == 0) ||
+ ((lock & PS_LOCK_X) && (idx == 0)) ||
+ ((lock & PS_LOCK_Y) && (idx == 1)) ||
+ ((lock & PS_LOCK_Z) && (idx == 2)))
+ {
+ /* just work on these channels one by one... there's no interaction between values */
+ pose_slide_apply_val(pso, fcu, &vec[fcu->array_index]);
+ }
}
/* free the temp path we got */
@@ -423,15 +492,15 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
float quat_prev[4], quat_next[4];
/* get 2 quats */
- quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrame);
- quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrame);
- quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrame);
- quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrame);
+ quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrameF);
+ quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrameF);
+ quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrameF);
+ quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrameF);
- quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrame);
- quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrame);
- quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrame);
- quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrame);
+ quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrameF);
+ quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrameF);
+ quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrameF);
+ quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrameF);
/* perform blending */
if (pso->mode == POSESLIDE_BREAKDOWN) {
@@ -483,6 +552,10 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
/* move out one step either side */
pso->prevFrame--;
pso->nextFrame++;
+
+ /* apply NLA mapping corrections so the frame lookups work */
+ pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
+ pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
}
/* for each link, handle each set of transforms */
@@ -494,17 +567,17 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
*/
bPoseChannel *pchan = pfl->pchan;
- if (pchan->flag & POSE_LOC) {
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
/* calculate these for the 'location' vector, and use location curves */
pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
}
- if (pchan->flag & POSE_SIZE) {
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
/* calculate these for the 'scale' vector, and use scale curves */
pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
}
- if (pchan->flag & POSE_ROT) {
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
/* everything depends on the rotation mode */
if (pchan->rotmode > 0) {
/* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
@@ -519,12 +592,12 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
}
}
- if (pchan->flag & POSE_BBONE_SHAPE) {
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) {
/* bbone properties - they all start a "bbone_" prefix */
pose_slide_apply_props(pso, pfl, "bbone_");
}
- if (pfl->oldprops) {
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) {
/* not strictly a transform, but custom properties contribute to the pose produced in many rigs
* (e.g. the facial rigs used in Sintel)
*/
@@ -553,9 +626,12 @@ static void pose_slide_reset(tPoseSlideOp *pso)
/* ------------------------------------ */
/* draw percentage indicator in header */
+// TODO: Include hints about locks here...
static void pose_slide_draw_status(tPoseSlideOp *pso)
{
char status_str[UI_MAX_DRAW_STR];
+ char limits_str[UI_MAX_DRAW_STR];
+ char axis_str[50];
char mode_str[32];
switch (pso->mode) {
@@ -575,16 +651,58 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
break;
}
+ switch (pso->axislock) {
+ case PS_LOCK_X:
+ BLI_strncpy(axis_str, "[X]/Y/Z axis only (X to clear)", sizeof(axis_str));
+ break;
+ case PS_LOCK_Y:
+ BLI_strncpy(axis_str, "X/[Y]/Z axis only (Y to clear)", sizeof(axis_str));
+ break;
+ case PS_LOCK_Z:
+ BLI_strncpy(axis_str, "X/Y/[Z] axis only (Z to clear)", sizeof(axis_str));
+ break;
+
+ default:
+ if (ELEM(pso->channels, PS_TFM_LOC, PS_TFM_ROT, PS_TFM_SIZE)) {
+ BLI_strncpy(axis_str, "X/Y/Z = Axis Constraint", sizeof(axis_str));
+ }
+ else {
+ axis_str[0] = '\0';
+ }
+ break;
+ }
+
+ switch (pso->channels) {
+ case PS_TFM_LOC:
+ BLI_snprintf(limits_str, sizeof(limits_str), "[G]/R/S/B/C - Location only (G to clear) | %s", axis_str);
+ break;
+ case PS_TFM_ROT:
+ BLI_snprintf(limits_str, sizeof(limits_str), "G/[R]/S/B/C - Rotation only (R to clear) | %s", axis_str);
+ break;
+ case PS_TFM_SIZE:
+ BLI_snprintf(limits_str, sizeof(limits_str), "G/R/[S]/B/C - Scale only (S to clear) | %s", axis_str);
+ break;
+ case PS_TFM_BBONE_SHAPE:
+ BLI_strncpy(limits_str, "G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s", sizeof(limits_str));
+ break;
+ case PS_TFM_PROPS:
+ BLI_strncpy(limits_str, "G/R/S/B/[C] - Custom Properties only (C to clear) | %s", sizeof(limits_str));
+ break;
+ default:
+ BLI_strncpy(limits_str, "G/R/S/B/C - Limit to Transform/Property Set", sizeof(limits_str));
+ break;
+ }
+
if (hasNumInput(&pso->num)) {
Scene *scene = pso->scene;
char str_offs[NUM_STR_REP_LEN];
outputNumInput(&pso->num, str_offs, &scene->unit);
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str);
}
else {
- BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f));
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %d %% | %s", mode_str, (int)(pso->percentage * 100.0f), limits_str);
}
ED_area_headerprint(pso->sa, status_str);
@@ -641,6 +759,10 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
pso->nextFrame = (ak->next) ? (ak->next->cfra) : (pso->cframe + 1);
RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
}
+
+ /* apply NLA mapping corrections so the frame lookups work */
+ pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
+ pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
}
else {
BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
@@ -675,11 +797,58 @@ static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso, wmOperator *op
RNA_float_set(op->ptr, "percentage", pso->percentage);
}
+/* handle an event to toggle channels mode */
+static void pose_slide_toggle_channels_mode(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_Channels channel)
+{
+ /* Turn channel on or off? */
+ if (pso->channels == channel) {
+ /* Already limiting to transform only, so pressing this again turns it off */
+ pso->channels = PS_TFM_ALL;
+ }
+ else {
+ /* Only this set of channels */
+ pso->channels = channel;
+ }
+ RNA_enum_set(op->ptr, "channels", pso->channels);
+
+
+ /* Reset axis limits too for good measure */
+ pso->axislock = 0;
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+}
+
+/* handle an event to toggle axis locks - returns whether any change in state is needed */
+static bool pose_slide_toggle_axis_locks(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_AxisLock axis)
+{
+ /* Axis can only be set when a transform is set - it doesn't make sense otherwise */
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE, PS_TFM_PROPS)) {
+ pso->axislock = 0;
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+ return false;
+ }
+
+ /* Turn on or off? */
+ if (pso->axislock == axis) {
+ /* Already limiting on this axis, so turn off */
+ pso->axislock = 0;
+ }
+ else {
+ /* Only this axis */
+ pso->axislock = axis;
+ }
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+
+ /* Setting changed, so pose update is needed */
+ return true;
+}
+
/* common code for modal() */
static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso = op->customdata;
wmWindow *win = CTX_wm_window(C);
+ bool do_pose_update = false;
+
const bool has_numinput = hasNumInput(&pso->num);
switch (event->type) {
@@ -718,7 +887,8 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* canceled! */
return OPERATOR_CANCELLED;
}
-
+
+ /* Percentage Chane... */
case MOUSEMOVE: /* calculate new position */
{
/* only handle mousemove if not doing numinput */
@@ -726,18 +896,13 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* update percentage based on position of mouse */
pose_slide_mouse_update_percentage(pso, op, event);
- /* update percentage indicator in header */
- pose_slide_draw_status(pso);
-
- /* reset transforms (to avoid accumulation errors) */
- pose_slide_reset(pso);
-
- /* apply... */
- pose_slide_apply(C, pso);
+ /* update pose to reflect the new values (see below) */
+ do_pose_update = true;
}
break;
}
default:
+ {
if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) {
float value;
@@ -751,21 +916,94 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
CLAMP(pso->percentage, 0.0f, 1.0f);
RNA_float_set(op->ptr, "percentage", pso->percentage);
- /* update percentage indicator in header */
- pose_slide_draw_status(pso);
-
- /* reset transforms (to avoid accumulation errors) */
- pose_slide_reset(pso);
-
- /* apply... */
- pose_slide_apply(C, pso);
+ /* Update pose to reflect the new values (see below) */
+ do_pose_update = true;
break;
}
+ else if (event->val == KM_PRESS) {
+ switch (event->type) {
+ /* Transform Channel Limits */
+ /* XXX: Replace these hardcoded hotkeys with a modalmap that can be customised */
+ case GKEY: /* Location */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_LOC);
+ do_pose_update = true;
+ break;
+ }
+ case RKEY: /* Rotation */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_ROT);
+ do_pose_update = true;
+ break;
+ }
+ case SKEY: /* Scale */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_SIZE);
+ do_pose_update = true;
+ break;
+ }
+ case BKEY: /* Bendy Bones */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_BBONE_SHAPE);
+ do_pose_update = true;
+ break;
+ }
+ case CKEY: /* Custom Properties */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_PROPS);
+ do_pose_update = true;
+ break;
+ }
+
+
+ /* Axis Locks */
+ /* XXX: Hardcoded... */
+ case XKEY:
+ {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_X)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+ case YKEY:
+ {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Y)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+ case ZKEY:
+ {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Z)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+
+
+ default: /* Some other unhandled key... */
+ break;
+ }
+ }
else {
/* unhandled event - maybe it was some view manip? */
/* allow to pass through */
return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
}
+ }
+ }
+
+
+ /* perform pose updates - in response to some user action (e.g. pressing a key or moving the mouse) */
+ if (do_pose_update) {
+ /* update percentage indicator in header */
+ pose_slide_draw_status(pso);
+
+ /* reset transforms (to avoid accumulation errors) */
+ pose_slide_reset(pso);
+
+ /* apply... */
+ pose_slide_apply(C, pso);
}
/* still running... */
@@ -795,11 +1033,16 @@ static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso
}
/* common code for defining RNA properties */
+/* TODO: Skip save on these? */
static void pose_slide_opdef_properties(wmOperatorType *ot)
{
+ RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for which keyframe is favored more", 0.3, 0.7);
+
RNA_def_int(ot->srna, "prev_frame", 0, MINAFRAME, MAXFRAME, "Previous Keyframe", "Frame number of keyframe immediately before the current frame", 0, 50);
RNA_def_int(ot->srna, "next_frame", 0, MINAFRAME, MAXFRAME, "Next Keyframe", "Frame number of keyframe immediately after the current frame", 0, 50);
- RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for the sliding operation", 0.3, 0.7);
+
+ RNA_def_enum(ot->srna, "channels", prop_channels_types, PS_TFM_ALL, "Channels", "Set of properties that are affected");
+ RNA_def_enum(ot->srna, "axis_lock", prop_axis_lock_types, 0, "Axis Lock", "Transform axis to restrict effects to");
}
/* ------------------------------------ */
@@ -1238,7 +1481,7 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu,
/* stop on matching marker if there is one */
for (ce = modeData.sel_markers.first; ce; ce = ce->next) {
- if (ce->cfra == iroundf(bezt->vec[1][0]))
+ if (ce->cfra == round_fl_to_int(bezt->vec[1][0]))
break;
}
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index b645f1fb2f3..063ba37f20d 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -36,6 +36,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
@@ -286,7 +287,7 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo
/* get the name - if flipping, we must flip this first */
if (flip)
- BKE_deform_flip_side_name(name, chan->name, false);
+ BLI_string_flip_side_name(name, chan->name, false, sizeof(name));
else
BLI_strncpy(name, chan->name, sizeof(name));
diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c
index 661a8e1de9f..2bcf3099104 100644
--- a/source/blender/editors/armature/reeb.c
+++ b/source/blender/editors/armature/reeb.c
@@ -2240,9 +2240,9 @@ static void glueByMergeSort(ReebGraph *rg, ReebArc *a0, ReebArc *a1, ReebEdge *e
else {
a1 = nextArcMappedToEdge(a1, e1);
}
+ }
}
}
-}
static void mergePaths(ReebGraph *rg, ReebEdge *e0, ReebEdge *e1, ReebEdge *e2)
{
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 856573ffab0..02c76a840f1 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -40,7 +40,7 @@ struct wmOperatorType;
struct ViewContext;
/* editfont.c */
-enum { DEL_ALL, DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL };
+enum { DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL };
enum { CASE_LOWER, CASE_UPPER };
enum { LINE_BEGIN, LINE_END, PREV_CHAR, NEXT_CHAR, PREV_WORD, NEXT_WORD,
PREV_LINE, NEXT_LINE, PREV_PAGE, NEXT_PAGE };
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index fce6425b9be..5d637b113d8 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -178,9 +178,10 @@ void ED_keymap_curve(wmKeyConfig *keyconf)
RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_style_toggle", PKEY, KM_PRESS, KM_CTRL, 0)->ptr, "style", CU_CHINFO_SMALLCAPS);
RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", DELKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_NEXT_SEL);
+ RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", DELKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_NEXT_WORD);
RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_PREV_SEL);
RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", DEL_PREV_SEL); /* same as above [#26623] */
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_ALL);
+ RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_PREV_WORD);
RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", HOMEKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_BEGIN);
RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index e40dde24ce2..844fcc7b379 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -91,14 +91,6 @@ typedef struct {
int flag;
} UndoCurve;
-/* Definitions needed for shape keys */
-typedef struct {
- void *orig_cv;
- int key_index, nu_index, pt_index, vertex_index;
- bool switched;
- Nurb *orig_nu;
-} CVKeyIndex;
-
void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus);
static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, const short flag, const bool split);
static int curve_delete_segments(Object *obedit, const bool split);
@@ -138,9 +130,9 @@ void printknots(Object *obedit)
/* ********************* Shape keys *************** */
-static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt_index, int vertex_index, Nurb *orig_nu)
+static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt_index, int vertex_index)
{
- CVKeyIndex *cvIndex = MEM_callocN(sizeof(CVKeyIndex), "init_cvKeyIndex");
+ CVKeyIndex *cvIndex = MEM_callocN(sizeof(CVKeyIndex), __func__);
cvIndex->orig_cv = cv;
cvIndex->key_index = key_index;
@@ -148,7 +140,6 @@ static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt
cvIndex->pt_index = pt_index;
cvIndex->vertex_index = vertex_index;
cvIndex->switched = false;
- cvIndex->orig_nu = orig_nu;
return cvIndex;
}
@@ -174,7 +165,12 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
origbezt = orignu->bezt;
pt_index = 0;
while (a--) {
- keyIndex = init_cvKeyIndex(origbezt, key_index, nu_index, pt_index, vertex_index, orignu);
+ /* We cannot keep *any* reference to curve obdata,
+ * it might be replaced and freed while editcurve remain in use (in viewport render case e.g.).
+ * Note that we could use a pool to avoid lots of malloc's here, but... not really a problem for now. */
+ BezTriple *origbezt_cpy = MEM_mallocN(sizeof(*origbezt), __func__);
+ *origbezt_cpy = *origbezt;
+ keyIndex = init_cvKeyIndex(origbezt_cpy, key_index, nu_index, pt_index, vertex_index);
BLI_ghash_insert(gh, bezt, keyIndex);
key_index += 12;
vertex_index += 3;
@@ -189,7 +185,12 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
origbp = orignu->bp;
pt_index = 0;
while (a--) {
- keyIndex = init_cvKeyIndex(origbp, key_index, nu_index, pt_index, vertex_index, orignu);
+ /* We cannot keep *any* reference to curve obdata,
+ * it might be replaced and freed while editcurve remain in use (in viewport render case e.g.).
+ * Note that we could use a pool to avoid lots of malloc's here, but... not really a problem for now. */
+ BPoint *origbp_cpy = MEM_mallocN(sizeof(*origbp_cpy), __func__);
+ *origbp_cpy = *origbp;
+ keyIndex = init_cvKeyIndex(origbp_cpy, key_index, nu_index, pt_index, vertex_index);
BLI_ghash_insert(gh, bp, keyIndex);
key_index += 4;
bp++;
@@ -250,23 +251,22 @@ static int getKeyIndexOrig_keyIndex(EditNurb *editnurb, void *cv)
return index->key_index;
}
-static void keyIndex_delCV(EditNurb *editnurb, const void *cv)
+static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt)
{
if (!editnurb->keyindex) {
return;
}
- BLI_ghash_remove(editnurb->keyindex, cv, NULL, MEM_freeN);
-}
-
-static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt)
-{
- keyIndex_delCV(editnurb, bezt);
+ BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bezt);
}
static void keyIndex_delBP(EditNurb *editnurb, BPoint *bp)
{
- keyIndex_delCV(editnurb, bp);
+ if (!editnurb->keyindex) {
+ return;
+ }
+
+ BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bp);
}
static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
@@ -282,7 +282,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
a = nu->pntsu;
while (a--) {
- BLI_ghash_remove(editnurb->keyindex, bezt, NULL, MEM_freeN);
+ BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bezt);
bezt++;
}
}
@@ -291,7 +291,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
a = nu->pntsu * nu->pntsv;
while (a--) {
- BLI_ghash_remove(editnurb->keyindex, bp, NULL, MEM_freeN);
+ BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bp);
bp++;
}
}
@@ -535,6 +535,7 @@ static GHash *dupli_keyIndexHash(GHash *keyindex)
CVKeyIndex *newIndex = MEM_mallocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index");
memcpy(newIndex, index, sizeof(CVKeyIndex));
+ newIndex->orig_cv = MEM_dupallocN(index->orig_cv);
BLI_ghash_insert(gh, cv, newIndex);
}
@@ -624,7 +625,7 @@ static void calc_keyHandles(ListBase *nurb, float *key)
}
}
-static void calc_shapeKeys(Object *obedit)
+static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
{
Curve *cu = (Curve *)obedit->data;
@@ -636,7 +637,7 @@ static void calc_shapeKeys(Object *obedit)
KeyBlock *actkey = BLI_findlink(&cu->key->block, editnurb->shapenr - 1);
BezTriple *bezt, *oldbezt;
BPoint *bp, *oldbp;
- Nurb *nu;
+ Nurb *nu, *newnu;
int totvert = BKE_nurbList_verts_count(&editnurb->nurbs);
float (*ofs)[3] = NULL;
@@ -706,20 +707,25 @@ static void calc_shapeKeys(Object *obedit)
currkey = cu->key->block.first;
while (currkey) {
- int apply_offset = (ofs && (currkey != actkey) && (editnurb->shapenr - 1 == currkey->relative));
+ const bool apply_offset = (ofs && (currkey != actkey) && (editnurb->shapenr - 1 == currkey->relative));
float *fp = newkey = MEM_callocN(cu->key->elemsize * totvert, "currkey->data");
ofp = oldkey = currkey->data;
nu = editnurb->nurbs.first;
+ /* We need to restore to original curve into newnurb, *not* editcurve's nurbs.
+ * Otherwise, in case we update obdata *without* leaving editmode (e.g. viewport render), we would
+ * invalidate editcurve. */
+ newnu = newnurbs->first;
i = 0;
while (nu) {
if (currkey == actkey) {
- int restore = actkey != cu->key->refkey;
+ const bool restore = actkey != cu->key->refkey;
if (nu->bezt) {
bezt = nu->bezt;
a = nu->pntsu;
+ BezTriple *newbezt = newnu->bezt;
while (a--) {
int j;
oldbezt = getKeyIndexOrig_bezt(editnurb, bezt);
@@ -728,7 +734,7 @@ static void calc_shapeKeys(Object *obedit)
copy_v3_v3(fp, bezt->vec[j]);
if (restore && oldbezt) {
- copy_v3_v3(bezt->vec[j], oldbezt->vec[j]);
+ copy_v3_v3(newbezt->vec[j], oldbezt->vec[j]);
}
fp += 3;
@@ -736,16 +742,18 @@ static void calc_shapeKeys(Object *obedit)
fp[0] = bezt->alfa;
if (restore && oldbezt) {
- bezt->alfa = oldbezt->alfa;
+ newbezt->alfa = oldbezt->alfa;
}
fp += 3; ++i; /* alphas */
bezt++;
+ newbezt++;
}
}
else {
bp = nu->bp;
a = nu->pntsu * nu->pntsv;
+ BPoint *newbp = newnu->bp;
while (a--) {
oldbp = getKeyIndexOrig_bp(editnurb, bp);
@@ -754,12 +762,13 @@ static void calc_shapeKeys(Object *obedit)
fp[3] = bp->alfa;
if (restore && oldbp) {
- copy_v3_v3(bp->vec, oldbp->vec);
- bp->alfa = oldbp->alfa;
+ copy_v3_v3(newbp->vec, oldbp->vec);
+ newbp->alfa = oldbp->alfa;
}
fp += 4;
bp++;
+ newbp++;
i += 2;
}
}
@@ -1204,9 +1213,13 @@ void ED_curve_editnurb_load(Object *obedit)
}
}
+ /* We have to pass also new copied nurbs, since we want to restore original curve (without edited shapekey)
+ * on obdata, but *not* on editcurve itself (ED_curve_editnurb_load call does not always implies freeing
+ * of editcurve, e.g. when called to generate render data...). */
+ calc_shapeKeys(obedit, &newnurb);
+
cu->nurb = newnurb;
- calc_shapeKeys(obedit);
ED_curve_updateAnimPaths(obedit->data);
BKE_nurbList_free(&oldnurb);
@@ -1227,13 +1240,11 @@ void ED_curve_editnurb_make(Object *obedit)
if (actkey) {
// XXX strcpy(G.editModeTitleExtra, "(Key) ");
undo_editmode_clear();
- BKE_keyblock_convert_to_curve(actkey, cu, &cu->nurb);
}
if (editnurb) {
BKE_nurbList_free(&editnurb->nurbs);
- BKE_curve_editNurb_keyIndex_free(editnurb);
- editnurb->keyindex = NULL;
+ BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex);
}
else {
editnurb = MEM_callocN(sizeof(EditNurb), "editnurb");
@@ -1248,12 +1259,16 @@ void ED_curve_editnurb_make(Object *obedit)
nu = nu->next;
}
- if (actkey)
- editnurb->shapenr = obedit->shapenr;
-
/* animation could be added in editmode even if there was no animdata in
* object mode hence we always need CVs index be created */
init_editNurb_keyIndex(editnurb, &cu->nurb);
+
+ if (actkey) {
+ editnurb->shapenr = obedit->shapenr;
+ /* Apply shapekey to new nurbs of editnurb, not those of original curve (and *after* we generated keyIndex),
+ * else we do not have valid 'original' data to properly restore curve when leaving editmode. */
+ BKE_keyblock_convert_to_curve(actkey, cu, &editnurb->nurbs);
+ }
}
}
@@ -1309,8 +1324,7 @@ static int separate_exec(bContext *C, wmOperator *op)
ED_curve_editnurb_make(newob);
newedit = newcu->editnurb;
BKE_nurbList_free(&newedit->nurbs);
- BKE_curve_editNurb_keyIndex_free(newedit);
- newedit->keyindex = NULL;
+ BKE_curve_editNurb_keyIndex_free(&newedit->keyindex);
BLI_movelisttolist(&newedit->nurbs, &newnurb);
/* 4. put old object out of editmode and delete separated geometry */
@@ -4146,7 +4160,7 @@ static int make_segment_exec(bContext *C, wmOperator *op)
*/
bp = nu->bp;
- if (bp[nu->pntsu - 1].f1 & SELECT) {
+ if (bp[nu->pntsu - 1].f1 & SELECT) {
if (nu2 == NULL) {
nu2 = nu;
}
@@ -4777,13 +4791,13 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
{
Nurb *nu;
- float minmax[2][3];
+ float center[3];
float temp[3];
- bool nu_has_select = false;
-
+ uint verts_len;
bool changed = false;
- INIT_MINMAX(minmax[0], minmax[1]);
+ zero_v3(center);
+ verts_len = 0;
for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
int i;
@@ -4792,8 +4806,8 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
for (i = 0, bezt = nu->bezt; i < nu->pntsu; i++, bezt++) {
if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
- minmax_v3v3_v3(UNPACK2(minmax), bezt->vec[1]);
- nu_has_select = true;
+ add_v3_v3(center, bezt->vec[1]);
+ verts_len += 1;
}
}
}
@@ -4802,18 +4816,18 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
for (i = 0, bp = nu->bp; i < nu->pntsu; i++, bp++) {
if (bp->f1 & SELECT) {
- minmax_v3v3_v3(UNPACK2(minmax), bp->vec);
- nu_has_select = true;
+ add_v3_v3(center, bp->vec);
+ verts_len += 1;
}
}
}
}
- if (nu_has_select && ed_editcurve_extrude(cu, editnurb)) {
- float ofs[3], center[3];
+ if (verts_len && ed_editcurve_extrude(cu, editnurb)) {
+ float ofs[3];
int i;
- mid_v3_v3v3(center, minmax[0], minmax[1]);
+ mul_v3_fl(center, 1.0f / (float)verts_len);
sub_v3_v3v3(ofs, location_init, center);
if ((cu->flag & CU_3D) == 0) {
@@ -4993,7 +5007,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
copy_v3_v3(location, ED_view3d_cursor3d_get(vc.scene, vc.v3d));
}
- ED_view3d_win_to_3d_int(vc.ar, location, event->mval, location);
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, location, event->mval, location);
if (use_proj) {
const float mval[2] = {UNPACK2(event->mval)};
@@ -5836,6 +5850,7 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
BLI_assert(points_stride + dims == points + (points_len * dims));
float tan_l[3], tan_r[3], error_sq_dummy;
+ unsigned int error_index_dummy;
sub_v3_v3v3(tan_l, bezt_prev->vec[1], bezt_prev->vec[2]);
normalize_v3(tan_l);
@@ -5846,7 +5861,7 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
points, points_len, NULL, dims, FLT_EPSILON,
tan_l, tan_r,
bezt_prev->vec[2], bezt_next->vec[0],
- &error_sq_dummy);
+ &error_sq_dummy, &error_index_dummy);
if (!ELEM(bezt_prev->h2, HD_FREE, HD_ALIGN)) {
bezt_prev->h2 = (bezt_prev->h2 == HD_VECT) ? HD_FREE : HD_ALIGN;
@@ -6033,6 +6048,9 @@ int join_curve_exec(bContext *C, wmOperator *op)
cu = ob->data;
BLI_movelisttolist(&cu->nurb, &tempbase);
+ /* Account for mixed 2D/3D curves when joining */
+ BKE_curve_curve_dimension_update(cu);
+
DAG_relations_tag_update(bmain); // because we removed object(s), call before editmode!
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
@@ -6110,7 +6128,7 @@ static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v)
BKE_nurbList_free(editbase);
if (undoCurve->undoIndex) {
- BLI_ghash_free(editnurb->keyindex, NULL, MEM_freeN);
+ BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex);
editnurb->keyindex = dupli_keyIndexHash(undoCurve->undoIndex);
}
@@ -6188,8 +6206,7 @@ static void free_undoCurve(void *ucv)
BKE_nurbList_free(&undoCurve->nubase);
- if (undoCurve->undoIndex)
- BLI_ghash_free(undoCurve->undoIndex, NULL, MEM_freeN);
+ BKE_curve_editNurb_keyIndex_free(&undoCurve->undoIndex);
free_fcurves(&undoCurve->fcurves);
free_fcurves(&undoCurve->drivers);
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 2d8fc76ee7e..4602945d11c 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -70,102 +70,6 @@
/* Distance between start/end points to consider cyclic */
#define STROKE_CYCLIC_DIST_PX 8
-
-/* -------------------------------------------------------------------- */
-
-/** \name Depth Utilities
- * \{ */
-
-
-static float depth_read_zbuf(const ViewContext *vc, int x, int y)
-{
- ViewDepths *vd = vc->rv3d->depths;
-
- if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
- return vd->depths[y * vd->w + x];
- else
- return -1.0f;
-}
-
-static bool depth_unproject(
- const ARegion *ar, const bglMats *mats,
- const int mval[2], const double depth,
- float r_location_world[3])
-{
- double p[3];
- if (gluUnProject(
- (double)ar->winrct.xmin + mval[0] + 0.5,
- (double)ar->winrct.ymin + mval[1] + 0.5,
- depth, mats->modelview, mats->projection, (const GLint *)mats->viewport,
- &p[0], &p[1], &p[2]))
- {
- copy_v3fl_v3db(r_location_world, p);
- return true;
- }
- return false;
-}
-
-static bool depth_read_normal(
- const ViewContext *vc, const bglMats *mats, const int mval[2],
- float r_normal[3])
-{
- /* pixels surrounding */
- bool depths_valid[9] = {false};
- float coords[9][3] = {{0}};
-
- ARegion *ar = vc->ar;
- const ViewDepths *depths = vc->rv3d->depths;
-
- for (int x = 0, i = 0; x < 2; x++) {
- for (int y = 0; y < 2; y++) {
- const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
-
- const double depth = (double)depth_read_zbuf(vc, mval_ofs[0], mval_ofs[1]);
- if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
- if (depth_unproject(ar, mats, mval_ofs, depth, coords[i])) {
- depths_valid[i] = true;
- }
- }
- i++;
- }
- }
-
- const int edges[2][6][2] = {
- /* x edges */
- {{0, 1}, {1, 2},
- {3, 4}, {4, 5},
- {6, 7}, {7, 8}},
- /* y edges */
- {{0, 3}, {3, 6},
- {1, 4}, {4, 7},
- {2, 5}, {5, 8}},
- };
-
- float cross[2][3] = {{0.0f}};
-
- for (int i = 0; i < 6; i++) {
- for (int axis = 0; axis < 2; axis++) {
- if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) {
- float delta[3];
- sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]);
- add_v3_v3(cross[axis], delta);
- }
- }
- }
-
- cross_v3_v3v3(r_normal, cross[0], cross[1]);
-
- if (normalize_v3(r_normal) != 0.0f) {
- return true;
- }
- else {
- return false;
- }
-}
-
-/** \} */
-
-
/* -------------------------------------------------------------------- */
/** \name StrokeElem / #RNA_OperatorStrokeElement Conversion Functions
@@ -308,9 +212,9 @@ static bool stroke_elem_project(
((unsigned int)mval_i[0] < depths->w) &&
((unsigned int)mval_i[1] < depths->h))
{
- const double depth = (double)depth_read_zbuf(&cdd->vc, mval_i[0], mval_i[1]);
+ const double depth = (double)ED_view3d_depth_read_cached(&cdd->vc, mval_i);
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
- if (depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) {
+ if (ED_view3d_depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) {
is_location_world_set = true;
if (r_normal_world) {
zero_v3(r_normal_world);
@@ -319,7 +223,7 @@ static bool stroke_elem_project(
if (surface_offset != 0.0f) {
const float offset = cdd->project.use_surface_offset_absolute ? 1.0f : radius;
float normal[3];
- if (depth_read_normal(&cdd->vc, &cdd->mats, mval_i, normal)) {
+ if (ED_view3d_depth_read_cached_normal(&cdd->vc, &cdd->mats, mval_i, normal)) {
madd_v3_v3fl(r_location_world, normal, offset * surface_offset);
if (r_normal_world) {
copy_v3_v3(r_normal_world, normal);
@@ -353,7 +257,7 @@ static bool stroke_elem_project_fallback(
surface_offset, radius,
r_location_world, r_normal_world);
if (is_depth_found == false) {
- ED_view3d_win_to_3d(cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world);
+ ED_view3d_win_to_3d(cdd->vc.v3d, cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world);
zero_v3(r_normal_local);
}
mul_v3_m4v3(r_location_local, cdd->vc.obedit->imat, r_location_world);
@@ -627,7 +531,7 @@ static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event)
CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW,
CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE))
{
- if (depth_read_normal(&cdd->vc, &cdd->mats, event->mval, normal)) {
+ if (ED_view3d_depth_read_cached_normal(&cdd->vc, &cdd->mats, event->mval, normal)) {
if (cps->surface_plane == CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW) {
float cross_a[3], cross_b[3];
cross_v3_v3v3(cross_a, rv3d->viewinv[2], normal);
@@ -876,7 +780,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
const float radius_range = cps->radius_max - cps->radius_min;
Nurb *nu = MEM_callocN(sizeof(Nurb), __func__);
- nu->pntsv = 1;
+ nu->pntsv = 0;
nu->resolu = cu->resolu;
nu->resolv = cu->resolv;
nu->flag |= CU_SMOOTH;
@@ -1135,7 +1039,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const float mval_fl[2] = {UNPACK2(event->mval)};
float center[3];
negate_v3_v3(center, cdd->vc.rv3d->ofs);
- ED_view3d_win_to_3d(cdd->vc.ar, center, mval_fl, cdd->prev.location_world);
+ ED_view3d_win_to_3d(cdd->vc.v3d, cdd->vc.ar, center, mval_fl, cdd->prev.location_world);
copy_v3_v3(cdd->prev.location_world_valid, cdd->prev.location_world);
}
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 57e731874b4..535e5d7bd28 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -1170,9 +1170,10 @@ void FONT_OT_line_break(wmOperatorType *ot)
/******************* delete operator **********************/
static EnumPropertyItem delete_type_items[] = {
- {DEL_ALL, "ALL", 0, "All", ""},
{DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
{DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
+ {DEL_NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
+ {DEL_PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
{DEL_SELECTION, "SELECTION", 0, "Selection", ""},
{DEL_NEXT_SEL, "NEXT_OR_SELECTION", 0, "Next or Selection", ""},
{DEL_PREV_SEL, "PREVIOUS_OR_SELECTION", 0, "Previous or Selection", ""},
@@ -1183,7 +1184,9 @@ static int delete_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
- int x, selstart, selend, type = RNA_enum_get(op->ptr, "type");
+ int selstart, selend, type = RNA_enum_get(op->ptr, "type");
+ int range[2] = {0, 0};
+ bool has_select = false;
if (ef->len == 0)
return OPERATOR_CANCELLED;
@@ -1191,6 +1194,7 @@ static int delete_exec(bContext *C, wmOperator *op)
if (BKE_vfont_select_get(obedit, &selstart, &selend)) {
if (type == DEL_NEXT_SEL) type = DEL_SELECTION;
else if (type == DEL_PREV_SEL) type = DEL_SELECTION;
+ has_select = true;
}
else {
if (type == DEL_NEXT_SEL) type = DEL_NEXT_CHAR;
@@ -1198,10 +1202,6 @@ static int delete_exec(bContext *C, wmOperator *op)
}
switch (type) {
- case DEL_ALL:
- ef->len = ef->pos = 0;
- ef->textbuf[0] = 0;
- break;
case DEL_SELECTION:
if (!kill_selection(obedit, 0))
return OPERATOR_CANCELLED;
@@ -1210,29 +1210,69 @@ static int delete_exec(bContext *C, wmOperator *op)
if (ef->pos <= 0)
return OPERATOR_CANCELLED;
- for (x = ef->pos; x <= ef->len; x++)
- ef->textbuf[x - 1] = ef->textbuf[x];
- for (x = ef->pos; x <= ef->len; x++)
- ef->textbufinfo[x - 1] = ef->textbufinfo[x];
+ range[0] = ef->pos - 1;
+ range[1] = ef->pos;
ef->pos--;
- ef->textbuf[--ef->len] = '\0';
break;
case DEL_NEXT_CHAR:
if (ef->pos >= ef->len)
return OPERATOR_CANCELLED;
- for (x = ef->pos; x < ef->len; x++)
- ef->textbuf[x] = ef->textbuf[x + 1];
- for (x = ef->pos; x < ef->len; x++)
- ef->textbufinfo[x] = ef->textbufinfo[x + 1];
+ range[0] = ef->pos;
+ range[1] = ef->pos + 1;
+ break;
+ case DEL_NEXT_WORD:
+ {
+ int pos = ef->pos;
+ BLI_str_cursor_step_wchar(ef->textbuf, ef->len, &pos, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, true);
+ range[0] = ef->pos;
+ range[1] = pos;
+ break;
+ }
- ef->textbuf[--ef->len] = '\0';
+ case DEL_PREV_WORD:
+ {
+ int pos = ef->pos;
+ BLI_str_cursor_step_wchar(ef->textbuf, ef->len, &pos, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, true);
+ range[0] = pos;
+ range[1] = ef->pos;
+ ef->pos = pos;
break;
+ }
default:
return OPERATOR_CANCELLED;
}
+ if (range[0] != range[1]) {
+ BLI_assert(range[0] < range[1]);
+ int len_remove = range[1] - range[0];
+ int len_tail = ef->len - range[1];
+ if (has_select) {
+ for (int i = 0; i < 2; i++) {
+ int *sel = i ? &ef->selend : &ef->selstart;
+ if (*sel <= range[0]) {
+ /* pass */
+ }
+ else if (*sel >= range[1]) {
+ *sel -= len_remove;
+ }
+ else if (*sel < range[1]) {
+ /* pass */
+ *sel = range[0];
+ }
+ }
+ }
+
+ memmove(&ef->textbuf[range[0]], &ef->textbuf[range[1]], sizeof(*ef->textbuf) * len_tail);
+ memmove(&ef->textbufinfo[range[0]], &ef->textbufinfo[range[1]], sizeof(*ef->textbufinfo) * len_tail);
+
+ ef->len -= len_remove;
+ ef->textbuf[ef->len] = '\0';
+
+ BKE_vfont_select_clamp(obedit);
+ }
+
text_update_edited(C, obedit, FO_EDIT);
return OPERATOR_FINISHED;
@@ -1253,7 +1293,7 @@ void FONT_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_enum(ot->srna, "type", delete_type_items, DEL_ALL, "Type", "Which part of the text to delete");
+ RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PREV_CHAR, "Type", "Which part of the text to delete");
}
/*********************** insert text operator *************************/
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 6604d595573..3d5317b2ebd 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -44,6 +44,7 @@ set(SRC
gpencil_convert.c
gpencil_data.c
gpencil_edit.c
+ gpencil_interpolate.c
gpencil_ops.c
gpencil_paint.c
gpencil_select.c
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 48786e08f85..c08ed0db400 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -528,15 +528,15 @@ static void gp_draw_stroke_fill(
}
else {
/* As an initial implementation, we use the OpenGL filled polygon drawing
- * here since it's the easiest option to implement for this case. It does
- * come with limitations (notably for concave shapes), though it shouldn't
- * be much of an issue in most cases.
- *
- * We keep this legacy implementation around despite now having the high quality
- * fills, as this is necessary for keeping everything working nicely for files
- * created using old versions of Blender which may have depended on the artifacts
- * the old fills created.
- */
+ * here since it's the easiest option to implement for this case. It does
+ * come with limitations (notably for concave shapes), though it shouldn't
+ * be much of an issue in most cases.
+ *
+ * We keep this legacy implementation around despite now having the high quality
+ * fills, as this is necessary for keeping everything working nicely for files
+ * created using old versions of Blender which may have depended on the artifacts
+ * the old fills created.
+ */
bGPDspoint *pt;
glBegin(GL_POLYGON);
@@ -701,24 +701,25 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
*/
{
bGPDspoint *pt1, *pt2;
- float pm[2];
+ float s0[2], s1[2]; /* segment 'center' points */
+ float pm[2]; /* normal from previous segment. */
int i;
float fpt[3];
glShadeModel(GL_FLAT);
glBegin(GL_QUADS);
-
+
+ /* get x and y coordinates from first point */
+ mul_v3_m4v3(fpt, diff_mat, &points->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
+
for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
- float s0[2], s1[2]; /* segment 'center' points */
float t0[2], t1[2]; /* tessellated coordinates */
float m1[2], m2[2]; /* gradient and normal */
float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
float pthick; /* thickness at segment point */
- /* get x and y coordinates from points */
- mul_v3_m4v3(fpt, diff_mat, &pt1->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
-
+ /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */
mul_v3_m4v3(fpt, diff_mat, &pt2->x);
gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1);
@@ -846,6 +847,8 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
glVertex2fv(t0);
}
+ /* store computed point2 coordinates as point1 ones of next segment. */
+ copy_v2_v2(s0, s1);
/* store stroke's 'natural' normal for next stroke to use */
copy_v2_v2(pm, m2);
}
@@ -1419,8 +1422,16 @@ static void gp_draw_data_layers(
#undef GP_DRAWFLAG_APPLY
- /* draw 'onionskins' (frame left + right) */
- if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) {
+ /* Draw 'onionskins' (frame left + right)
+ * - It is only possible to show these if the option is enabled
+ * - The "no onions" flag prevents ghosts from appearing during animation playback/scrubbing
+ * and in renders
+ * - The per-layer "always show" flag however overrides the playback/render restriction,
+ * allowing artists to selectively turn onionskins on/off during playback
+ */
+ if ((gpl->flag & GP_LAYER_ONIONSKIN) &&
+ ((dflag & GP_DRAWDATA_NO_ONIONS) == 0 || (gpl->flag & GP_LAYER_GHOST_ALWAYS)))
+ {
/* Drawing method - only immediately surrounding (gstep = 0),
* or within a frame range on either side (gstep > 0)
*/
@@ -1554,8 +1565,17 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
int cfra, int dflag, const char spacetype)
{
bGPdata *gpd_source = NULL;
-
+ ToolSettings *ts;
+ bGPDbrush *brush = NULL;
if (scene) {
+ ts = scene->toolsettings;
+ brush = BKE_gpencil_brush_getactive(ts);
+ /* if no brushes, create default set */
+ if (brush == NULL) {
+ BKE_gpencil_brush_init_presets(ts);
+ brush = BKE_gpencil_brush_getactive(ts);
+ }
+
if (spacetype == SPACE_VIEW3D) {
gpd_source = (scene->gpd ? scene->gpd : NULL);
}
@@ -1563,23 +1583,18 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
/* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */
gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
}
-
+
if (gpd_source) {
- ToolSettings *ts = scene->toolsettings;
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
if (brush != NULL) {
gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source,
offsx, offsy, winx, winy, cfra, dflag);
}
-
}
}
/* scene/clip data has already been drawn, only object/track data is drawn here
* if gpd_source == gpd, we don't have any object/track data and we can skip */
if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
- ToolSettings *ts = scene->toolsettings;
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
if (brush != NULL) {
gp_draw_data(brush, ts->gp_sculpt.alpha, gpd,
offsx, offsy, winx, winy, cfra, dflag);
@@ -1717,10 +1732,10 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg
rctf rectf;
ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */
- offsx = iroundf(rectf.xmin);
- offsy = iroundf(rectf.ymin);
- winx = iroundf(rectf.xmax - rectf.xmin);
- winy = iroundf(rectf.ymax - rectf.ymin);
+ offsx = round_fl_to_int(rectf.xmin);
+ offsy = round_fl_to_int(rectf.ymin);
+ winx = round_fl_to_int(rectf.xmax - rectf.xmin);
+ winy = round_fl_to_int(rectf.ymax - rectf.ymin);
}
else {
offsx = 0;
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index bd4856f1b93..90d44503013 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -252,8 +252,10 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl)
for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
gpfn = gpf->next;
- if (gpf->flag & GP_FRAME_SELECT)
- changed |= BKE_gpencil_layer_delframe(gpl, gpf);
+ if (gpf->flag & GP_FRAME_SELECT) {
+ BKE_gpencil_layer_delframe(gpl, gpf);
+ changed = true;
+ }
}
return changed;
@@ -314,7 +316,7 @@ void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type)
*/
/* globals for copy/paste data (like for other copy/paste buffers) */
-ListBase gp_anim_copybuf = {NULL, NULL};
+static ListBase gp_anim_copybuf = {NULL, NULL};
static int gp_anim_copy_firstframe = 999999999;
static int gp_anim_copy_lastframe = -999999999;
static int gp_anim_copy_cfra = 0;
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 8576cbca239..e5fb162a96c 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -297,9 +297,9 @@ static bool gp_brush_strength_apply(
float inf;
/* Compute strength of effect
- * - We divide the strength by 10, so that users can set "sane" values.
- * Otherwise, good default values are in the range of 0.093
- */
+ * - We divide the strength by 10, so that users can set "sane" values.
+ * Otherwise, good default values are in the range of 0.093
+ */
inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
/* apply */
@@ -710,7 +710,7 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
}
else {
/* ERROR */
- BLI_assert("3D stroke being sculpted in non-3D view");
+ BLI_assert(!"3D stroke being sculpted in non-3D view");
}
}
else {
@@ -773,6 +773,9 @@ typedef struct tGPSB_CloneBrushData {
/* for "stamp" mode, the currently pasted brushes */
bGPDstroke **new_strokes;
+
+ /* mapping from colors referenced per stroke, to the new colours in the "pasted" strokes */
+ GHash *new_colors;
} tGPSB_CloneBrushData;
/* Initialise "clone" brush data */
@@ -816,6 +819,11 @@ static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso)
if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems, "cloned strokes ptr array");
}
+
+ /* Init colormap for mapping between the pasted stroke's source colour(names)
+ * and the final colours that will be used here instead...
+ */
+ data->new_colors = gp_copybuf_validate_colormap(gso->gpd);
}
/* Free custom data used for "clone" brush */
@@ -829,6 +837,12 @@ static void gp_brush_clone_free(tGP_BrushEditData *gso)
data->new_strokes = NULL;
}
+ /* free copybuf colormap */
+ if (data->new_colors) {
+ BLI_ghash_free(data->new_colors, NULL, NULL);
+ data->new_colors = NULL;
+ }
+
/* free the customdata itself */
MEM_freeN(data);
gso->customdata = NULL;
@@ -869,6 +883,13 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
new_stroke->next = new_stroke->prev = NULL;
BLI_addtail(&gpf->strokes, new_stroke);
+ /* Fix color references */
+ BLI_assert(new_stroke->colorname[0] != '\0');
+ new_stroke->palcolor = BLI_ghash_lookup(data->new_colors, new_stroke->colorname);
+
+ BLI_assert(new_stroke->palcolor != NULL);
+ BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname));
+
/* Adjust all the stroke's points, so that the strokes
* get pasted relative to where the cursor is now
*/
@@ -1798,6 +1819,12 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
case UPARROWKEY:
case DOWNARROWKEY:
return OPERATOR_PASS_THROUGH;
+
+ /* Camera/View Manipulations - Allowed */
+ /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
+ case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
+ case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
+ return OPERATOR_PASS_THROUGH;
/* Unhandled event */
default:
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index c502ed1aa83..d0f68c4b8f3 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -191,7 +191,7 @@ static void gp_strokepoint_convertcoords(
}
}
- ED_view3d_win_to_3d(ar, fp, mvalf, p3d);
+ ED_view3d_win_to_3d(v3d, ar, fp, mvalf, p3d);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index ae83e899649..6980ad46241 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -42,6 +42,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 15f65b394a9..55a3fc09f2e 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -38,8 +38,11 @@
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -74,7 +77,6 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_view3d.h"
-#include "ED_screen.h"
#include "ED_space_api.h"
#include "gpencil_intern.h"
@@ -336,11 +338,27 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot)
/* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */
ListBase gp_strokes_copypastebuf = {NULL, NULL};
+/* Hash for hanging on to all the palette colors used by strokes in the buffer
+ *
+ * This is needed to prevent dangling and unsafe pointers when pasting across datablocks,
+ * or after a color used by a stroke in the buffer gets deleted (via user action or undo).
+ */
+static GHash *gp_strokes_copypastebuf_colors = NULL;
+
/* Free copy/paste buffer data */
void ED_gpencil_strokes_copybuf_free(void)
{
bGPDstroke *gps, *gpsn;
+ /* Free the palettes buffer
+ * NOTE: This is done before the strokes so that the name ptrs (keys) are still safe
+ */
+ if (gp_strokes_copypastebuf_colors) {
+ BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, MEM_freeN);
+ gp_strokes_copypastebuf_colors = NULL;
+ }
+
+ /* Free the stroke buffer */
for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) {
gpsn = gps->next;
@@ -353,6 +371,46 @@ void ED_gpencil_strokes_copybuf_free(void)
gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL;
}
+/* Ensure that destination datablock has all the colours the pasted strokes need
+ * Helper function for copy-pasting strokes
+ */
+GHash *gp_copybuf_validate_colormap(bGPdata *gpd)
+{
+ GHash *new_colors = BLI_ghash_str_new("GPencil Paste Dst Colors");
+ GHashIterator gh_iter;
+
+ /* If there's no active palette yet (i.e. new datablock), add one */
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ if (palette == NULL) {
+ palette = BKE_gpencil_palette_addnew(gpd, "Pasted Palette", true);
+ }
+
+ /* For each color, figure out what to map to... */
+ GHASH_ITER(gh_iter, gp_strokes_copypastebuf_colors) {
+ bGPDpalettecolor *palcolor;
+ char *name = BLI_ghashIterator_getKey(&gh_iter);
+
+ /* Look for existing color to map to */
+ /* XXX: What to do if same name but different color? Behaviour here should depend on a property? */
+ palcolor = BKE_gpencil_palettecolor_getbyname(palette, name);
+ if (palcolor == NULL) {
+ /* Doesn't Exist - Create new matching color for this palette */
+ /* XXX: This still doesn't fix the pasting across file boundaries problem... */
+ bGPDpalettecolor *src_color = BLI_ghashIterator_getValue(&gh_iter);
+
+ palcolor = MEM_dupallocN(src_color);
+ BLI_addtail(&palette->colors, palcolor);
+
+ BLI_uniquename(&palette->colors, palcolor, DATA_("GP Color"), '.', offsetof(bGPDpalettecolor, info), sizeof(palcolor->info));
+ }
+
+ /* Store this mapping (for use later when pasting) */
+ BLI_ghash_insert(new_colors, name, palcolor);
+ }
+
+ return new_colors;
+}
+
/* --------------------- */
/* Copy selected strokes */
@@ -414,7 +472,26 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- /* done - no updates needed */
+ /* Build up hash of colors used in these strokes, making copies of these to protect against dangling pointers */
+ if (gp_strokes_copypastebuf.first) {
+ gp_strokes_copypastebuf_colors = BLI_ghash_str_new("GPencil CopyBuf Colors");
+
+ for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ if (BLI_ghash_haskey(gp_strokes_copypastebuf_colors, gps->colorname) == false) {
+ bGPDpalettecolor *color = MEM_dupallocN(gps->palcolor);
+
+ BLI_ghash_insert(gp_strokes_copypastebuf_colors, gps->colorname, color);
+ gps->palcolor = color;
+ }
+ }
+ }
+ }
+
+ /* updates (to ensure operator buttons are refreshed, when used via hotkeys) */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); // XXX?
+
+ /* done */
return OPERATOR_FINISHED;
}
@@ -459,6 +536,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
bGPDframe *gpf;
eGP_PasteMode type = RNA_enum_get(op->ptr, "type");
+ GHash *new_colors;
/* check for various error conditions */
if (gpd == NULL) {
@@ -516,6 +594,10 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
+ /* Ensure that all the necessary colors exist */
+ new_colors = gp_copybuf_validate_colormap(gpd);
+
+ /* Copy over the strokes from the buffer (and adjust the colors) */
for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use(C, gps)) {
/* Need to verify if layer exists */
@@ -534,6 +616,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
*/
gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
if (gpf) {
+ /* Create new stroke */
bGPDstroke *new_stroke = MEM_dupallocN(gps);
new_stroke->tmp_layerinfo[0] = '\0';
@@ -544,10 +627,22 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
new_stroke->next = new_stroke->prev = NULL;
BLI_addtail(&gpf->strokes, new_stroke);
+
+ /* Fix color references */
+ BLI_assert(new_stroke->colorname[0] != '\0');
+ new_stroke->palcolor = BLI_ghash_lookup(new_colors, new_stroke->colorname);
+
+ BLI_assert(new_stroke->palcolor != NULL);
+ BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname));
+
+ /*new_stroke->flag |= GP_STROKE_RECALC_COLOR; */
}
}
}
+ /* free temp data */
+ BLI_ghash_free(new_colors, NULL, NULL);
+
/* updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -682,6 +777,87 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
}
+/* ********************* Add Blank Frame *************************** */
+
+/* Basically the same as the drawing op */
+static int UNUSED_FUNCTION(gp_blank_frame_add_poll)(bContext *C)
+{
+ if (ED_operator_regionactive(C)) {
+ /* check if current context can support GPencil data */
+ if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
+ return 1;
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
+ }
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ }
+
+ return 0;
+}
+
+static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd);
+
+ const bool all_layers = RNA_boolean_get(op->ptr, "all_layers");
+
+ /* Initialise datablock and an active layer if nothing exists yet */
+ if (ELEM(NULL, gpd, active_gpl)) {
+ /* let's just be lazy, and call the "Add New Layer" operator, which sets everything up as required */
+ WM_operator_name_call(C, "GPENCIL_OT_layer_add", WM_OP_EXEC_DEFAULT, NULL);
+ }
+
+ /* Go through each layer, adding a frame after the active one
+ * and/or shunting all the others out of the way
+ */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ if ((all_layers == false) && (gpl != active_gpl)) {
+ continue;
+ }
+
+ /* 1) Check for an existing frame on the current frame */
+ bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, CFRA);
+ if (gpf) {
+ /* Shunt all frames after (and including) the existing one later by 1-frame */
+ for (; gpf; gpf = gpf->next) {
+ gpf->framenum += 1;
+ }
+ }
+
+ /* 2) Now add a new frame, with nothing in it */
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_blank_frame_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Insert Blank Frame";
+ ot->idname = "GPENCIL_OT_blank_frame_add";
+ ot->description = "Insert a blank frame on the current frame "
+ "(all subsequently existing frames, if any, are shifted right by one frame)";
+
+ /* callbacks */
+ ot->exec = gp_blank_frame_add_exec;
+ ot->poll = gp_add_poll;
+
+ /* properties */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_boolean(ot->srna, "all_layers", false, "All Layers", "Create blank frame in all layers, not only active");
+}
+
/* ******************* Delete Active Frame ************************ */
static int gp_actframe_delete_poll(bContext *C)
@@ -872,6 +1048,9 @@ static int gp_dissolve_selected_points(bContext *C)
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ continue;
if (gps->flag & GP_STROKE_SELECT) {
bGPDspoint *pt;
@@ -1084,6 +1263,9 @@ static int gp_delete_selected_points(bContext *C)
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ continue;
if (gps->flag & GP_STROKE_SELECT) {
@@ -1123,7 +1305,7 @@ static int gp_delete_exec(bContext *C, wmOperator *op)
case GP_DELETEOP_POINTS: /* selected points (breaks the stroke into segments) */
result = gp_delete_selected_points(C);
break;
-
+
case GP_DELETEOP_FRAME: /* active frame */
result = gp_actframe_delete_exec(C, op);
break;
@@ -1897,6 +2079,13 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
/* ***************** Reproject Strokes ********************** */
+typedef enum eGP_ReprojectModes {
+ /* On same plane, parallel to viewplane */
+ GP_REPROJECT_PLANAR = 0,
+ /* Reprojected on to the scene geometry */
+ GP_REPROJECT_SURFACE,
+} eGP_ReprojectModes;
+
static int gp_strokes_reproject_poll(bContext *C)
{
/* 2 Requirements:
@@ -1906,14 +2095,23 @@ static int gp_strokes_reproject_poll(bContext *C)
return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C));
}
-static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op))
+static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
GP_SpaceConversion gsc = {NULL};
+ eGP_ReprojectModes mode = RNA_boolean_get(op->ptr, "type");
/* init space conversion stuff */
gp_point_conversion_init(C, &gsc);
+ /* init autodist for geometry projection */
+ if (mode == GP_REPROJECT_SURFACE) {
+ view3d_region_operator_needs_opengl(CTX_wm_window(C), gsc.ar);
+ ED_view3d_autodist_init(scene, gsc.ar, CTX_wm_view3d(C), 0);
+ }
+
+ // TODO: For deforming geometry workflow, create new frames?
+
/* Go through each editable + selected stroke, adjusting each of its points one by one... */
GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
@@ -1949,7 +2147,27 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op))
/* Project screenspace back to 3D space (from current perspective)
* so that all points have been treated the same way
*/
- gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+ if (mode == GP_REPROJECT_PLANAR) {
+ /* Planar - All on same plane parallel to the viewplane */
+ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+ }
+ else {
+ /* Geometry - Snap to surfaces of visible geometry */
+ /* XXX: There will be precision loss (possible stairstep artifacts) from this conversion to satisfy the API's */
+ const int screen_co[2] = {(int)xy[0], (int)xy[1]};
+
+ int depth_margin = 0; // XXX: 4 for strokes, 0 for normal
+ float depth;
+
+ /* XXX: The proper procedure computes the depths into an array, to have smooth transitions when all else fails... */
+ if (ED_view3d_autodist_depth(gsc.ar, screen_co, depth_margin, &depth)) {
+ ED_view3d_autodist_simple(gsc.ar, screen_co, &pt->x, 0, &depth);
+ }
+ else {
+ /* Default to planar */
+ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+ }
+ }
/* Unapply parent corrections */
if (gpl->parent) {
@@ -1966,21 +2184,36 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op))
void GPENCIL_OT_reproject(wmOperatorType *ot)
{
+ static EnumPropertyItem reproject_type[] = {
+ {GP_REPROJECT_PLANAR, "PLANAR", 0, "Planar",
+ "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint "
+ "using 'Cursor' Stroke Placement"},
+ {GP_REPROJECT_SURFACE, "SURFACE", 0, "Surface",
+ "Reproject the strokes on to the scene geometry, as if drawn using 'Surface' placement"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Reproject Strokes";
ot->idname = "GPENCIL_OT_reproject";
- ot->description = "Reproject the selected strokes from the current viewpoint to get all points on the same plane again "
- "(e.g. to fix problems from accidental 3D cursor movement, or viewport changes)";
+ ot->description = "Reproject the selected strokes from the current viewpoint as if they had been newly drawn "
+ "(e.g. to fix problems from accidental 3D cursor movement or accidental viewport changes, "
+ "or for matching deforming geometry)";
/* callbacks */
+ ot->invoke = WM_menu_invoke;
ot->exec = gp_strokes_reproject_exec;
ot->poll = gp_strokes_reproject_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", reproject_type, GP_REPROJECT_PLANAR, "Projection Type", "");
}
/* ******************* Stroke subdivide ************************** */
+
/* helper: Count how many points need to be inserted */
static int gp_count_subdivision_cuts(bGPDstroke *gps)
{
@@ -1989,10 +2222,10 @@ static int gp_count_subdivision_cuts(bGPDstroke *gps)
int totnewpoints = 0;
for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
- if (i + 1 < gps->totpoints){
+ if (i + 1 < gps->totpoints) {
if (gps->points[i + 1].flag & GP_SPOINT_SELECT) {
++totnewpoints;
- };
+ }
}
}
}
@@ -2047,7 +2280,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
/* if next point is selected add a half way point */
if (pt->flag & GP_SPOINT_SELECT) {
- if (i + 1 < oldtotpoints){
+ if (i + 1 < oldtotpoints) {
if (temp_points[i + 1].flag & GP_SPOINT_SELECT) {
pt_final = &gps->points[i2];
/* Interpolate all values */
@@ -2059,7 +2292,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
pt_final->time = interpf(pt->time, next->time, 0.5f);
pt_final->flag |= GP_SPOINT_SELECT;
++i2;
- };
+ }
}
}
}
@@ -2098,673 +2331,3 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-
-/* ========= Interpolation operators ========================== */
-/* Helper: Update point with interpolation */
-static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor)
-{
- bGPDspoint *prev, *pt, *next;
-
- /* update points */
- for (int i = 0; i < new_stroke->totpoints; i++) {
- prev = &gps_from->points[i];
- pt = &new_stroke->points[i];
- next = &gps_to->points[i];
-
- /* Interpolate all values */
- interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor);
- pt->pressure = interpf(prev->pressure, next->pressure, factor);
- pt->strength = interpf(prev->strength, next->strength, factor);
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- }
-}
-
-/* Helper: Update all strokes interpolated */
-static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
-{
- tGPDinterpolate_layer *tgpil;
- bGPDstroke *new_stroke, *gps_from, *gps_to;
- int cStroke;
- float factor;
- float shift = tgpi->shift;
-
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
- factor = tgpil->factor + shift;
- for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) {
- if (new_stroke->totpoints == 0) {
- continue;
- }
- /* get strokes to interpolate */
- cStroke = BLI_findindex(&tgpil->interFrame->strokes, new_stroke);
- gps_from = BLI_findlink(&tgpil->prevFrame->strokes, cStroke);
- gps_to = BLI_findlink(&tgpil->nextFrame->strokes, cStroke);
- /* update points position */
- if ((gps_from) && (gps_to)) {
- gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
- }
- }
- }
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
-}
-
-/* Helper: Verify valid strokes for interpolation */
-static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- int flag = ts->gp_sculpt.flag;
-
- bGPDlayer *gpl;
- bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
- bGPDstroke *gps_from, *gps_to;
- int fFrame;
-
- /* get layers */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* all layers or only active */
- if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
- continue;
- }
- /* only editable and visible layers are considered */
- if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
- continue;
- }
- /* read strokes */
- for (gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) {
- /* only selected */
- if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
- continue;
- }
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
- continue;
- }
- /* get final stroke to interpolate */
- fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from);
- gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame);
- if (gps_to == NULL) {
- continue;
- }
- return 1;
- }
- }
- return 0;
-}
-
-/* Helper: Create internal strokes interpolated */
-static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
-{
- bGPDlayer *gpl;
- bGPdata *gpd = tgpi->gpd;
- tGPDinterpolate_layer *tgpil;
- bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
- bGPDstroke *gps_from, *gps_to, *new_stroke;
- int fFrame;
-
- /* save initial factor for active layer to define shift limits */
- tgpi->init_factor = (float)(tgpi->cframe - active_gpl->actframe->framenum) / (active_gpl->actframe->next->framenum - active_gpl->actframe->framenum + 1);
- /* limits are 100% below 0 and 100% over the 100% */
- tgpi->low_limit = -1.0f - tgpi->init_factor;
- tgpi->high_limit = 2.0f - tgpi->init_factor;
-
- /* set layers */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* all layers or only active */
- if (((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
- continue;
- }
- /* only editable and visible layers are considered */
- if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
- continue;
- }
- /* create temp data for each layer */
- tgpil = NULL;
- tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
-
- tgpil->gpl = gpl;
- tgpil->prevFrame = gpl->actframe;
- tgpil->nextFrame = gpl->actframe->next;
-
- BLI_addtail(&tgpi->ilayers, tgpil);
- /* create a new temporary frame */
- tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe");
- tgpil->interFrame->framenum = tgpi->cframe;
-
- /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */
- tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1);
- /* create new strokes data with interpolated points reading original stroke */
- for (gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
- bool valid = true;
- /* only selected */
- if ((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
- valid = false;
- }
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
- valid = false;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) {
- valid = false;
- }
- /* get final stroke to interpolate */
- fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from);
- gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame);
- if (gps_to == NULL) {
- valid = false;
- }
- /* create new stroke */
- new_stroke = MEM_dupallocN(gps_from);
- new_stroke->points = MEM_dupallocN(gps_from->points);
- new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
- if (valid) {
- /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
- if (gps_from->totpoints > gps_to->totpoints) {
- new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
- new_stroke->totpoints = gps_to->totpoints;
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_CACHES;
- }
- /* update points position */
- gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
- }
- else {
- /* need an empty stroke to keep index correct for lookup, but resize to smallest size */
- new_stroke->totpoints = 0;
- new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
- new_stroke->tot_triangles = 0;
- new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles));
- }
- /* add to strokes */
- BLI_addtail(&tgpil->interFrame->strokes, new_stroke);
- }
- }
-}
-
-/* Helper: calculate shift based on position of mouse (we only use x-axis for now.
-* since this is more convenient for users to do), and store new shift value
-*/
-static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event)
-{
- float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f;
- float mpos = event->x - tgpi->ar->winrct.xmin;
- if (mpos >= mid) {
- tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid;
- }
- else {
- tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid);
- }
-
- CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
- RNA_float_set(op->ptr, "shift", tgpi->shift);
-}
-
-/* Helper: Draw status message while the user is running the operator */
-static void gpencil_interpolate_status_indicators(tGPDinterpolate *p)
-{
- Scene *scene = p->scene;
- char status_str[UI_MAX_DRAW_STR];
- char msg_str[UI_MAX_DRAW_STR];
- BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust, Factor"), UI_MAX_DRAW_STR);
-
- if (hasNumInput(&p->num)) {
- char str_offs[NUM_STR_REP_LEN];
-
- outputNumInput(&p->num, str_offs, &scene->unit);
-
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
- }
- else {
- BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", msg_str, (int)((p->init_factor + p->shift) * 100.0f));
- }
-
- ED_area_headerprint(p->sa, status_str);
-}
-
-/* Helper: Update screen and stroke */
-static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
-{
- /* update shift indicator in header */
- gpencil_interpolate_status_indicators(tgpi);
- /* apply... */
- tgpi->shift = RNA_float_get(op->ptr, "shift");
- /* update points position */
- gp_interpolate_update_strokes(C, tgpi);
-}
-
-/* init new temporary interpolation data */
-static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
-
- /* set current scene and window */
- tgpi->scene = CTX_data_scene(C);
- tgpi->sa = CTX_wm_area(C);
- tgpi->ar = CTX_wm_region(C);
- tgpi->flag = ts->gp_sculpt.flag;
-
- /* set current frame number */
- tgpi->cframe = tgpi->scene->r.cfra;
-
- /* set GP datablock */
- tgpi->gpd = gpd;
-
- /* set interpolation weight */
- tgpi->shift = RNA_float_get(op->ptr, "shift");
- /* set layers */
- gp_interpolate_set_points(C, tgpi);
-
- return 1;
-}
-
-/* Poll handler: check if context is suitable for interpolation */
-static int gpencil_interpolate_poll(bContext *C)
-{
- bGPdata * gpd = CTX_data_gpencil_data(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- /* only 3D view */
- if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) {
- return 0;
- }
- /* need data to interpolate */
- if (ELEM(NULL, gpd, gpl)) {
- return 0;
- }
-
- return 1;
-}
-
-/* Allocate memory and initialize values */
-static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op)
-{
- tGPDinterpolate *tgpi = NULL;
-
- /* create new context data */
- tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data");
-
- /* define initial values */
- gp_interpolate_set_init_values(C, op, tgpi);
-
- /* return context data for running operator */
- return tgpi;
-}
-
-/* Exit and free memory */
-static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
-{
- tGPDinterpolate *tgpi = op->customdata;
- tGPDinterpolate_layer *tgpil;
-
- /* don't assume that operator data exists at all */
- if (tgpi) {
- /* remove drawing handler */
- if (tgpi->draw_handle_screen) {
- ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen);
- }
- if (tgpi->draw_handle_3d) {
- ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d);
- }
- /* clear status message area */
- ED_area_headerprint(tgpi->sa, NULL);
- /* finally, free memory used by temp data */
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
- BKE_gpencil_free_strokes(tgpil->interFrame);
- MEM_freeN(tgpil->interFrame);
- }
-
- BLI_freelistN(&tgpi->ilayers);
- MEM_freeN(tgpi);
- }
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
-
- /* clear pointer */
- op->customdata = NULL;
-}
-
-/* Cancel handler */
-static void gpencil_interpolate_cancel(bContext *C, wmOperator *op)
-{
- /* this is just a wrapper around exit() */
- gpencil_interpolate_exit(C, op);
-}
-
-/* Init interpolation: Allocate memory and set init values */
-static int gpencil_interpolate_init(bContext *C, wmOperator *op)
-{
- tGPDinterpolate *tgpi;
- /* check context */
- tgpi = op->customdata = gp_session_init_interpolation(C, op);
- if (tgpi == NULL) {
- /* something wasn't set correctly in context */
- gpencil_interpolate_exit(C, op);
- return 0;
- }
-
- /* everything is now setup ok */
- return 1;
-}
-
-/* ********************** custom drawcall api ***************** */
-/* Helper: drawing callback for modal operator in screen mode */
-static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
-{
- wmOperator *op = arg;
- struct tGPDinterpolate *tgpi = op->customdata;
- ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL);
-}
-
-/* Helper: drawing callback for modal operator in 3d mode */
-static void gpencil_interpolate_draw_3d(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
-{
- wmOperator *op = arg;
- struct tGPDinterpolate *tgpi = op->customdata;
- ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW);
-}
-
-/* Invoke handler: Initialize the operator */
-static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- wmWindow *win = CTX_wm_window(C);
- Scene *scene = CTX_data_scene(C);
- bGPdata * gpd = CTX_data_gpencil_data(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- tGPDinterpolate *tgpi = NULL;
-
- /* cannot interpolate if not between 2 frames */
- if ((gpl->actframe == NULL) || (gpl->actframe->next == NULL)) {
- BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer");
- return OPERATOR_CANCELLED;
- }
-
- /* cannot interpolate in extremes */
- if ((gpl->actframe->framenum == scene->r.cfra) || (gpl->actframe->next->framenum == scene->r.cfra)) {
- BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer");
- return OPERATOR_CANCELLED;
- }
-
- /* need editable strokes */
- if (!gp_interpolate_check_todo(C, gpd)) {
- BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable stroke");
- return OPERATOR_CANCELLED;
- }
-
- /* try to initialize context data needed */
- if (!gpencil_interpolate_init(C, op)) {
- if (op->customdata)
- MEM_freeN(op->customdata);
- return OPERATOR_CANCELLED;
- }
- else
- tgpi = op->customdata;
-
- /* enable custom drawing handlers. It needs 2 handlers because can be strokes in 3d space and screen space and each handler use different
- coord system */
- tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, op, REGION_DRAW_POST_PIXEL);
- tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, op, REGION_DRAW_POST_VIEW);
- /* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
- /* update shift indicator in header */
- gpencil_interpolate_status_indicators(tgpi);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
-
- /* add a modal handler for this operator */
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-/* Modal handler: Events handling during interactive part */
-static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- tGPDinterpolate *tgpi = op->customdata;
- wmWindow *win = CTX_wm_window(C);
- bGPDframe *gpf_dst;
- bGPDstroke *gps_src, *gps_dst;
- tGPDinterpolate_layer *tgpil;
- const bool has_numinput = hasNumInput(&tgpi->num);
-
- switch (event->type) {
- case LEFTMOUSE: /* confirm */
- case RETKEY:
- {
- /* return to normal cursor and header status */
- ED_area_headerprint(tgpi->sa, NULL);
- WM_cursor_modal_restore(win);
-
- /* insert keyframes as required... */
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
- gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
- gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN;
-
- /* copy strokes */
- BLI_listbase_clear(&gpf_dst->strokes);
- for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) {
- if (gps_src->totpoints == 0) {
- continue;
- }
- /* make copy of source stroke, then adjust pointer to points too */
- gps_dst = MEM_dupallocN(gps_src);
- gps_dst->points = MEM_dupallocN(gps_src->points);
- gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
- gps_dst->flag |= GP_STROKE_RECALC_CACHES;
- BLI_addtail(&gpf_dst->strokes, gps_dst);
- }
- }
- /* clean up temp data */
- gpencil_interpolate_exit(C, op);
-
- /* done! */
- return OPERATOR_FINISHED;
- }
-
- case ESCKEY: /* cancel */
- case RIGHTMOUSE:
- {
- /* return to normal cursor and header status */
- ED_area_headerprint(tgpi->sa, NULL);
- WM_cursor_modal_restore(win);
-
- /* clean up temp data */
- gpencil_interpolate_exit(C, op);
-
- /* canceled! */
- return OPERATOR_CANCELLED;
- }
- case WHEELUPMOUSE:
- {
- tgpi->shift = tgpi->shift + 0.01f;
- CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
- RNA_float_set(op->ptr, "shift", tgpi->shift);
- /* update screen */
- gpencil_interpolate_update(C, op, tgpi);
- break;
- }
- case WHEELDOWNMOUSE:
- {
- tgpi->shift = tgpi->shift - 0.01f;
- CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
- RNA_float_set(op->ptr, "shift", tgpi->shift);
- /* update screen */
- gpencil_interpolate_update(C, op, tgpi);
- break;
- }
- case MOUSEMOVE: /* calculate new position */
- {
- /* only handle mousemove if not doing numinput */
- if (has_numinput == false) {
- /* update shift based on position of mouse */
- gpencil_mouse_update_shift(tgpi, op, event);
- /* update screen */
- gpencil_interpolate_update(C, op, tgpi);
- }
- break;
- }
- default:
- if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
- float value;
- float factor = tgpi->init_factor;
-
- /* Grab shift from numeric input, and store this new value (the user see an int) */
- value = (factor + tgpi->shift) * 100.0f;
- applyNumInput(&tgpi->num, &value);
- tgpi->shift = value / 100.0f;
- /* recalculate the shift to get the right value in the frame scale */
- tgpi->shift = tgpi->shift - factor;
-
- CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
- RNA_float_set(op->ptr, "shift", tgpi->shift);
-
- /* update screen */
- gpencil_interpolate_update(C, op, tgpi);
-
- break;
- }
- else {
- /* unhandled event - allow to pass through */
- return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
- }
- }
-
- /* still running... */
- return OPERATOR_RUNNING_MODAL;
-}
-
-/* Define modal operator for interpolation */
-void GPENCIL_OT_interpolate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Grease Pencil Interpolation";
- ot->idname = "GPENCIL_OT_interpolate";
- ot->description = "Interpolate grease pencil strokes between frames";
-
- /* api callbacks */
- ot->invoke = gpencil_interpolate_invoke;
- ot->modal = gpencil_interpolate_modal;
- ot->cancel = gpencil_interpolate_cancel;
- ot->poll = gpencil_interpolate_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Displacement factor for the interpolate operation", -0.9f, 0.9f);
-}
-
-/* =============== Interpolate sequence ===============*/
-/* Create Sequence Interpolation */
-static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- bGPdata * gpd = CTX_data_gpencil_data(C);
- bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
- bGPDlayer *gpl;
- bGPDframe *prevFrame, *nextFrame, *interFrame;
- bGPDstroke *gps_from, *gps_to, *new_stroke;
- float factor;
- int cframe, fFrame;
- int flag = ts->gp_sculpt.flag;
-
- /* cannot interpolate if not between 2 frames */
- if ((active_gpl->actframe == NULL) || (active_gpl->actframe->next == NULL)) {
- BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames");
- return OPERATOR_CANCELLED;
- }
- /* cannot interpolate in extremes */
- if ((active_gpl->actframe->framenum == scene->r.cfra) || (active_gpl->actframe->next->framenum == scene->r.cfra)) {
- BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames");
- return OPERATOR_CANCELLED;
- }
-
- /* loop all layer to check if need interpolation */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* all layers or only active */
- if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
- continue;
- }
- /* only editable and visible layers are considered */
- if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
- continue;
- }
- /* store extremes */
- prevFrame = gpl->actframe;
- nextFrame = gpl->actframe->next;
- /* Loop over intermediary frames and create the interpolation */
- for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) {
- interFrame = NULL;
-
- /* get interpolation factor */
- factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1);
-
- /* create new strokes data with interpolated points reading original stroke */
- for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
- /* only selected */
- if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
- continue;
- }
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
- continue;
- }
- /* get final stroke to interpolate */
- fFrame = BLI_findindex(&prevFrame->strokes, gps_from);
- gps_to = BLI_findlink(&nextFrame->strokes, fFrame);
- if (gps_to == NULL) {
- continue;
- }
- /* create a new frame if needed */
- if (interFrame == NULL) {
- interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW);
- interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
- }
- /* create new stroke */
- new_stroke = MEM_dupallocN(gps_from);
- new_stroke->points = MEM_dupallocN(gps_from->points);
- new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
- /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
- if (gps_from->totpoints > gps_to->totpoints) {
- new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
- new_stroke->totpoints = gps_to->totpoints;
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_CACHES;
- }
- /* update points position */
- gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
-
- /* add to strokes */
- BLI_addtail(&interFrame->strokes, new_stroke);
- }
- }
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-/* Define sequence interpolation */
-void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Grease Pencil Sequence Interpolation";
- ot->idname = "GPENCIL_OT_interpolate_sequence";
- ot->description = "Interpolate full grease pencil strokes sequence between frames";
-
- /* api callbacks */
- ot->exec = gpencil_interpolate_seq_exec;
- ot->poll = gpencil_interpolate_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-/* ========= End Interpolation operators ========================== */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index e2e5fc28710..a3734c56c59 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -40,6 +40,8 @@ struct bGPdata;
struct bGPDstroke;
struct bGPDspoint;
+struct GHash;
+
struct ARegion;
struct View2D;
struct wmOperatorType;
@@ -69,75 +71,23 @@ typedef struct GP_SpaceConversion {
float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */
} GP_SpaceConversion;
-
-/**
- * Check whether a given stroke segment is inside a circular brush
- *
- * \param mval The current screen-space coordinates (midpoint) of the brush
- * \param mvalo The previous screen-space coordinates (midpoint) of the brush (NOT CURRENTLY USED)
- * \param rad The radius of the brush
- *
- * \param x0, y0 The screen-space x and y coordinates of the start of the stroke segment
- * \param x1, y1 The screen-space x and y coordinates of the end of the stroke segment
- */
bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
int rad, int x0, int y0, int x1, int y1);
-
-/**
- * Init settings for stroke point space conversions
- *
- * \param[out] r_gsc The space conversion settings struct, populated with necessary params
- */
void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
-/**
- * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
- *
- * \param[out] r_x The screen-space x-coordinate of the point
- * \param[out] r_y The screen-space y-coordinate of the point
- */
void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct bGPDspoint *pt,
int *r_x, int *r_y);
-/**
- * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
- *
- * Just like gp_point_to_xy(), except the resulting coordinates are floats not ints.
- * Use this version to solve "stair-step" artifacts which may arise when roundtripping the calculations.
- *
- * \param[out] r_x The screen-space x-coordinate of the point
- * \param[out] r_y The screen-space y-coordinate of the point
- */
void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
float *r_x, float *r_y);
-/**
- * Convert point to parent space
- *
- * \param pt Original point
- * \param diff_mat Matrix with the difference between original parent matrix
- * \param[out] r_pt Pointer to new point after apply matrix
- */
void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt);
-/**
- * Change points position relative to parent object
- */
+
void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps);
-/**
- * Change point position relative to parent object
- */
+
void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt);
-/**
- * Convert a screenspace point to a 3D Grease Pencil coordinate.
- *
- * For use with editing tools where it is easier to perform the operations in 2D,
- * and then later convert the transformed points back to 3D.
- *
- * \param screeN_co The screenspace 2D coordinates to convert to
- * \param[out] r_out The resulting 3D coordinates of the input point
- */
bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, struct Scene *scene, const float screen_co[2], float r_out[3]);
/* Poll Callbacks ------------------------------------ */
@@ -155,48 +105,18 @@ int gp_brush_crt_presets_poll(bContext *C);
extern ListBase gp_strokes_copypastebuf;
+/* Build a map for converting between old colornames and destination-color-refs */
+struct GHash *gp_copybuf_validate_colormap(bGPdata *gpd);
+
/* Stroke Editing ------------------------------------ */
void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags);
-/**
- * Apply smooth to stroke point
- * \param gps Stroke to smooth
- * \param i Point index
- * \param inf Amount of smoothing to apply
- * \param affect_pressure Apply smoothing to pressure values too?
- */
bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure);
-
-/**
-* Apply smooth for strength to stroke point
-* \param gps Stroke to smooth
-* \param i Point index
-* \param inf Amount of smoothing to apply
-*/
bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf);
-
-/**
-* Apply smooth for thickness to stroke point (use pressure)
-* \param gps Stroke to smooth
-* \param i Point index
-* \param inf Amount of smoothing to apply
-*/
bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf);
-
-/**
- * Subdivide a stroke once, by adding points at the midpoint between each pair of points
- * \param gps Stroke data
- * \param new_totpoints Total number of points (after subdividing)
- */
void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints);
-
-/**
-* Add randomness to stroke
-* \param gps Stroke data
-* \param brush Brush data
-*/
void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush);
/* Layers Enums -------------------------------------- */
@@ -287,6 +207,8 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot);
void GPENCIL_OT_layer_merge(struct wmOperatorType *ot);
+void GPENCIL_OT_blank_frame_add(struct wmOperatorType *ot);
+
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
@@ -340,6 +262,7 @@ void gpencil_undo_finish(void);
void GPENCIL_OT_interpolate(struct wmOperatorType *ot);
void GPENCIL_OT_interpolate_sequence(struct wmOperatorType *ot);
+void GPENCIL_OT_interpolate_reverse(struct wmOperatorType *ot);
/* ****************************************************** */
/* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
new file mode 100644
index 00000000000..83e2a85db49
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -0,0 +1,1142 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for interpolating new Grease Pencil frames from existing strokes
+ */
+
+/** \file blender/editors/gpencil/gpencil_interpolate.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_easing.h"
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_color_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_space_api.h"
+
+#include "gpencil_intern.h"
+
+/* ************************************************ */
+/* Core/Shared Utilities */
+
+/* Poll callback for interpolation operators */
+static int gpencil_view3d_poll(bContext *C)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+
+ /* only 3D view */
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype != SPACE_VIEW3D) {
+ return 0;
+ }
+
+ /* need data to interpolate */
+ if (ELEM(NULL, gpd, gpl)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Perform interpolation */
+static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor)
+{
+ bGPDspoint *prev, *pt, *next;
+
+ /* update points */
+ for (int i = 0; i < new_stroke->totpoints; i++) {
+ prev = &gps_from->points[i];
+ pt = &new_stroke->points[i];
+ next = &gps_to->points[i];
+
+ /* Interpolate all values */
+ interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor);
+ pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor);
+ pt->strength = interpf(prev->strength, next->strength, 1.0f - factor);
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+}
+
+/* ****************** Interpolate Interactive *********************** */
+
+/* Helper: Update all strokes interpolated */
+static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
+{
+ tGPDinterpolate_layer *tgpil;
+ const float shift = tgpi->shift;
+
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ bGPDstroke *new_stroke;
+ const float factor = tgpil->factor + shift;
+
+ for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) {
+ bGPDstroke *gps_from, *gps_to;
+ int stroke_idx;
+
+ if (new_stroke->totpoints == 0) {
+ continue;
+ }
+
+ /* get strokes to interpolate */
+ stroke_idx = BLI_findindex(&tgpil->interFrame->strokes, new_stroke);
+
+ gps_from = BLI_findlink(&tgpil->prevFrame->strokes, stroke_idx);
+ gps_to = BLI_findlink(&tgpil->nextFrame->strokes, stroke_idx);
+
+ /* update points position */
+ if ((gps_from) && (gps_to)) {
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+}
+
+/* Helper: Verify valid strokes for interpolation */
+static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag;
+
+ /* get layers */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* all layers or only active */
+ if (!(flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* read strokes */
+ for (bGPDstroke *gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) {
+ bGPDstroke *gps_to;
+ int fFrame;
+
+ /* only selected */
+ if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ continue;
+ }
+
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from);
+ gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame);
+ if (gps_to == NULL) {
+ continue;
+ }
+
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Helper: Create internal strokes interpolated */
+static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
+{
+ bGPdata *gpd = tgpi->gpd;
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDframe *actframe = active_gpl->actframe;
+
+ /* save initial factor for active layer to define shift limits */
+ tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) / (actframe->next->framenum - actframe->framenum + 1);
+
+ /* limits are 100% below 0 and 100% over the 100% */
+ tgpi->low_limit = -1.0f - tgpi->init_factor;
+ tgpi->high_limit = 2.0f - tgpi->init_factor;
+
+ /* set layers */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ tGPDinterpolate_layer *tgpil;
+
+ /* all layers or only active */
+ if (!(tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* create temp data for each layer */
+ tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
+
+ tgpil->gpl = gpl;
+ tgpil->prevFrame = gpl->actframe;
+ tgpil->nextFrame = gpl->actframe->next;
+
+ BLI_addtail(&tgpi->ilayers, tgpil);
+
+ /* create a new temporary frame */
+ tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe");
+ tgpil->interFrame->framenum = tgpi->cframe;
+
+ /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */
+ tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1);
+
+ /* create new strokes data with interpolated points reading original stroke */
+ for (bGPDstroke *gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
+ bGPDstroke *gps_to;
+ int fFrame;
+
+ bGPDstroke *new_stroke;
+ bool valid = true;
+
+
+ /* only selected */
+ if ((tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ valid = false;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ valid = false;
+ }
+
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) {
+ valid = false;
+ }
+
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from);
+ gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame);
+ if (gps_to == NULL) {
+ valid = false;
+ }
+
+ /* create new stroke */
+ new_stroke = MEM_dupallocN(gps_from);
+ new_stroke->points = MEM_dupallocN(gps_from->points);
+ new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+
+ if (valid) {
+ /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
+ if (gps_from->totpoints > gps_to->totpoints) {
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+ new_stroke->totpoints = gps_to->totpoints;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ }
+ /* update points position */
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
+ }
+ else {
+ /* need an empty stroke to keep index correct for lookup, but resize to smallest size */
+ new_stroke->totpoints = 0;
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
+ new_stroke->tot_triangles = 0;
+ new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles));
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ }
+
+ /* add to strokes */
+ BLI_addtail(&tgpil->interFrame->strokes, new_stroke);
+ }
+ }
+}
+
+/* ----------------------- */
+/* Drawing Callbacks */
+
+/* Drawing callback for modal operator in screen mode */
+static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
+ ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL);
+}
+
+/* Drawing callback for modal operator in 3d mode */
+static void gpencil_interpolate_draw_3d(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
+ ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW);
+}
+
+/* ----------------------- */
+
+/* Helper: calculate shift based on position of mouse (we only use x-axis for now.
+ * since this is more convenient for users to do), and store new shift value
+ */
+static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event)
+{
+ float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f;
+ float mpos = event->x - tgpi->ar->winrct.xmin;
+
+ if (mpos >= mid) {
+ tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid;
+ }
+ else {
+ tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid);
+ }
+
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+}
+
+/* Helper: Draw status message while the user is running the operator */
+static void gpencil_interpolate_status_indicators(tGPDinterpolate *p)
+{
+ Scene *scene = p->scene;
+ char status_str[UI_MAX_DRAW_STR];
+ char msg_str[UI_MAX_DRAW_STR];
+
+ BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"), UI_MAX_DRAW_STR);
+
+ if (hasNumInput(&p->num)) {
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&p->num, str_offs, &scene->unit);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", msg_str, (int)((p->init_factor + p->shift) * 100.0f));
+ }
+
+ ED_area_headerprint(p->sa, status_str);
+}
+
+/* Update screen and stroke */
+static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
+{
+ /* update shift indicator in header */
+ gpencil_interpolate_status_indicators(tgpi);
+ /* apply... */
+ tgpi->shift = RNA_float_get(op->ptr, "shift");
+ /* update points position */
+ gp_interpolate_update_strokes(C, tgpi);
+}
+
+/* ----------------------- */
+
+/* Exit and free memory */
+static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi = op->customdata;
+ tGPDinterpolate_layer *tgpil;
+
+ /* don't assume that operator data exists at all */
+ if (tgpi) {
+ /* remove drawing handler */
+ if (tgpi->draw_handle_screen) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen);
+ }
+ if (tgpi->draw_handle_3d) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d);
+ }
+
+ /* clear status message area */
+ ED_area_headerprint(tgpi->sa, NULL);
+
+ /* finally, free memory used by temp data */
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ BKE_gpencil_free_strokes(tgpil->interFrame);
+ MEM_freeN(tgpil->interFrame);
+ }
+
+ BLI_freelistN(&tgpi->ilayers);
+ MEM_freeN(tgpi);
+ }
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* clear pointer */
+ op->customdata = NULL;
+}
+
+/* Init new temporary interpolation data */
+static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+
+ /* set current scene and window */
+ tgpi->scene = CTX_data_scene(C);
+ tgpi->sa = CTX_wm_area(C);
+ tgpi->ar = CTX_wm_region(C);
+ tgpi->flag = ts->gp_interpolate.flag;
+
+ /* set current frame number */
+ tgpi->cframe = tgpi->scene->r.cfra;
+
+ /* set GP datablock */
+ tgpi->gpd = gpd;
+
+ /* set interpolation weight */
+ tgpi->shift = RNA_float_get(op->ptr, "shift");
+ /* set layers */
+ gp_interpolate_set_points(C, tgpi);
+
+ return 1;
+}
+
+/* Allocate memory and initialize values */
+static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data");
+
+ /* define initial values */
+ gp_interpolate_set_init_values(C, op, tgpi);
+
+ /* return context data for running operator */
+ return tgpi;
+}
+
+/* Init interpolation: Allocate memory and set init values */
+static int gpencil_interpolate_init(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi;
+
+ /* check context */
+ tgpi = op->customdata = gp_session_init_interpolation(C, op);
+ if (tgpi == NULL) {
+ /* something wasn't set correctly in context */
+ gpencil_interpolate_exit(C, op);
+ return 0;
+ }
+
+ /* everything is now setup ok */
+ return 1;
+}
+
+/* ----------------------- */
+
+/* Invoke handler: Initialize the operator */
+static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ bGPDframe *actframe = gpl->actframe;
+ tGPDinterpolate *tgpi = NULL;
+
+ /* cannot interpolate if not between 2 frames */
+ if (ELEM(NULL, actframe, actframe->next)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* cannot interpolate in extremes */
+ if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* need editable strokes */
+ if (!gp_interpolate_check_todo(C, gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable strokes");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* try to initialize context data needed */
+ if (!gpencil_interpolate_init(C, op)) {
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ tgpi = op->customdata;
+ }
+
+ /* Enable custom drawing handlers
+ * It needs 2 handlers because strokes can in 3d space and screen space
+ * and each handler use different coord system
+ */
+ tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, tgpi, REGION_DRAW_POST_PIXEL);
+ tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
+
+ /* set cursor to indicate modal */
+ WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+
+ /* update shift indicator in header */
+ gpencil_interpolate_status_indicators(tgpi);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* add a modal handler for this operator */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal handler: Events handling during interactive part */
+static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPDinterpolate *tgpi = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+ bGPDframe *gpf_dst;
+ bGPDstroke *gps_src, *gps_dst;
+ tGPDinterpolate_layer *tgpil;
+ const bool has_numinput = hasNumInput(&tgpi->num);
+
+ switch (event->type) {
+ case LEFTMOUSE: /* confirm */
+ case RETKEY:
+ {
+ /* return to normal cursor and header status */
+ ED_area_headerprint(tgpi->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* insert keyframes as required... */
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
+ gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN;
+
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) {
+ if (gps_src->totpoints == 0) {
+ continue;
+ }
+
+ /* make copy of source stroke, then adjust pointer to points too */
+ gps_dst = MEM_dupallocN(gps_src);
+ gps_dst->points = MEM_dupallocN(gps_src->points);
+ gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
+ gps_dst->flag |= GP_STROKE_RECALC_CACHES;
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+ }
+ }
+
+ /* clean up temp data */
+ gpencil_interpolate_exit(C, op);
+
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY: /* cancel */
+ case RIGHTMOUSE:
+ {
+ /* return to normal cursor and header status */
+ ED_area_headerprint(tgpi->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* clean up temp data */
+ gpencil_interpolate_exit(C, op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+
+ case WHEELUPMOUSE:
+ {
+ tgpi->shift = tgpi->shift + 0.01f;
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ break;
+ }
+ case WHEELDOWNMOUSE:
+ {
+ tgpi->shift = tgpi->shift - 0.01f;
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ break;
+ }
+ case MOUSEMOVE: /* calculate new position */
+ {
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* update shift based on position of mouse */
+ gpencil_mouse_update_shift(tgpi, op, event);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ }
+ break;
+ }
+ default:
+ {
+ if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
+ const float factor = tgpi->init_factor;
+ float value;
+
+ /* Grab shift from numeric input, and store this new value (the user see an int) */
+ value = (factor + tgpi->shift) * 100.0f;
+ applyNumInput(&tgpi->num, &value);
+ tgpi->shift = value / 100.0f;
+
+ /* recalculate the shift to get the right value in the frame scale */
+ tgpi->shift = tgpi->shift - factor;
+
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+
+ break;
+ }
+ else {
+ /* unhandled event - allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
+ }
+ }
+
+ /* still running... */
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Cancel handler */
+static void gpencil_interpolate_cancel(bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ gpencil_interpolate_exit(C, op);
+}
+
+void GPENCIL_OT_interpolate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Interpolation";
+ ot->idname = "GPENCIL_OT_interpolate";
+ ot->description = "Interpolate grease pencil strokes between frames";
+
+ /* callbacks */
+ ot->invoke = gpencil_interpolate_invoke;
+ ot->modal = gpencil_interpolate_modal;
+ ot->cancel = gpencil_interpolate_cancel;
+ ot->poll = gpencil_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Bias factor for which frame has more influence on the interpolated strokes", -0.9f, 0.9f);
+}
+
+/* ****************** Interpolate Sequence *********************** */
+
+/* Helper: Perform easing equation calculations for GP interpolation operator */
+static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_settings, float time)
+{
+ const float begin = 0.0f;
+ const float change = 1.0f;
+ const float duration = 1.0f;
+
+ const float back = ipo_settings->back;
+ const float amplitude = ipo_settings->amplitude;
+ const float period = ipo_settings->period;
+
+ eBezTriple_Easing easing = ipo_settings->easing;
+ float result = time;
+
+ switch (ipo_settings->type) {
+ case GP_IPO_BACK:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_back_ease_in(time, begin, change, duration, back);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_back_ease_out(time, begin, change, duration, back);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_back_ease_in_out(time, begin, change, duration, back);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_back_ease_out(time, begin, change, duration, back);
+ break;
+ }
+ break;
+
+ case GP_IPO_BOUNCE:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_bounce_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_bounce_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_bounce_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_bounce_ease_out(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_CIRC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_circ_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_circ_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_circ_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_circ_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_CUBIC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_cubic_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_cubic_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_cubic_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_cubic_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_ELASTIC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
+ break;
+ }
+ break;
+
+ case GP_IPO_EXPO:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_expo_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_expo_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_expo_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_expo_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUAD:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quad_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quad_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quad_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quad_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUART:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quart_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quart_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quart_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quart_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUINT:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quint_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quint_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quint_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quint_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_SINE:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_sine_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_sine_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_sine_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_sine_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ default:
+ printf("%s: Unknown interpolation type - %d\n", __func__, ipo_settings->type);
+ break;
+ }
+
+ return result;
+}
+
+static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDframe *actframe = active_gpl->actframe;
+
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate;
+ eGP_Interpolate_SettingsFlag flag = ipo_settings->flag;
+
+ /* cannot interpolate if not between 2 frames */
+ if (ELEM(NULL, actframe, actframe->next)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer");
+ return OPERATOR_CANCELLED;
+ }
+ /* cannot interpolate in extremes */
+ if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* loop all layer to check if need interpolation */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *prevFrame, *nextFrame;
+ bGPDstroke *gps_from, *gps_to;
+ int cframe, fFrame;
+
+ /* all layers or only active */
+ if (((flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* store extremes */
+ prevFrame = gpl->actframe;
+ nextFrame = gpl->actframe->next;
+
+ /* Loop over intermediary frames and create the interpolation */
+ for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) {
+ bGPDframe *interFrame = NULL;
+ float factor;
+
+ /* get interpolation factor */
+ factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1);
+
+ if (ipo_settings->type == GP_IPO_CURVEMAP) {
+ /* custom curvemap */
+ if (ipo_settings->custom_ipo) {
+ factor = curvemapping_evaluateF(ipo_settings->custom_ipo, 0, factor);
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Custom interpolation curve does not exist");
+ }
+ }
+ else if (ipo_settings->type >= GP_IPO_BACK) {
+ /* easing equation... */
+ factor = gp_interpolate_seq_easing_calc(ipo_settings, factor);
+ }
+
+ /* create new strokes data with interpolated points reading original stroke */
+ for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
+ bGPDstroke *new_stroke;
+
+ /* only selected */
+ if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ continue;
+ }
+
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&prevFrame->strokes, gps_from);
+ gps_to = BLI_findlink(&nextFrame->strokes, fFrame);
+ if (gps_to == NULL) {
+ continue;
+ }
+
+ /* create a new frame if needed */
+ if (interFrame == NULL) {
+ interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW);
+ interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
+ }
+
+ /* create new stroke */
+ new_stroke = MEM_dupallocN(gps_from);
+ new_stroke->points = MEM_dupallocN(gps_from->points);
+ new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
+ if (gps_from->totpoints > gps_to->totpoints) {
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+ new_stroke->totpoints = gps_to->totpoints;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ }
+
+ /* update points position */
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+
+ /* add to strokes */
+ BLI_addtail(&interFrame->strokes, new_stroke);
+ }
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Interpolate Sequence";
+ ot->idname = "GPENCIL_OT_interpolate_sequence";
+ ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames";
+
+ /* api callbacks */
+ ot->exec = gpencil_interpolate_seq_exec;
+ ot->poll = gpencil_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************** Remove Breakdowns ************************ */
+
+static int gpencil_interpolate_reverse_poll(bContext *C)
+{
+ if (!gpencil_view3d_poll(C)) {
+ return 0;
+ }
+
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+
+ /* need to be on a breakdown frame */
+ if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN)) {
+ CTX_wm_operator_poll_msg_set(C, "Expected current frame to be a breakdown");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ /* Go through each layer, deleting the breakdowns around the current frame,
+ * but only if there is a keyframe nearby to stop at
+ */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *start_key = NULL;
+ bGPDframe *end_key = NULL;
+ bGPDframe *gpf, *gpfn;
+
+ /* Only continue if we're currently on a breakdown keyframe */
+ if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN))
+ continue;
+
+ /* Search left for "start_key" (i.e. the first breakdown to remove) */
+ gpf = gpl->actframe;
+ while (gpf) {
+ if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
+ /* A breakdown... keep going left */
+ start_key = gpf;
+ gpf = gpf->prev;
+ }
+ else {
+ /* Not a breakdown (may be a key, or an extreme, or something else that wasn't generated)... stop */
+ break;
+ }
+ }
+
+ /* Search right for "end_key" (i.e. the last breakdown to remove) */
+ gpf = gpl->actframe;
+ while (gpf) {
+ if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
+ /* A breakdown... keep going right */
+ end_key = gpf;
+ gpf = gpf->next;
+ }
+ else {
+ /* Not a breakdown... stop */
+ break;
+ }
+ }
+
+ /* Did we find anything? */
+ /* NOTE: We should only proceed if there's something before/after these extents...
+ * Otherwise, there's just an extent of breakdowns with no keys to interpolate between
+ */
+ if ((start_key && end_key) &&
+ ELEM(NULL, start_key->prev, end_key->next) == false)
+ {
+ /* Set actframe to the key before start_key, since the keys have been removed now */
+ gpl->actframe = start_key->prev;
+
+ /* Free each frame we're removing (except the last one) */
+ for (gpf = start_key; gpf && gpf != end_key; gpf = gpfn) {
+ gpfn = gpf->next;
+
+ /* free strokes and their associated memory */
+ BKE_gpencil_free_strokes(gpf);
+ BLI_freelinkN(&gpl->frames, gpf);
+ }
+
+ /* Now free the last one... */
+ BKE_gpencil_free_strokes(end_key);
+ BLI_freelinkN(&gpl->frames, end_key);
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_interpolate_reverse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Breakdowns";
+ ot->idname = "GPENCIL_OT_interpolate_reverse";
+ ot->description = "Remove breakdown frames generated by interpolating between two Grease Pencil frames";
+
+ /* callbacks */
+ ot->exec = gpencil_interpolate_reverse_exec;
+ ot->poll = gpencil_interpolate_reverse_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* *************************************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 057d53ea458..3a2169798e5 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -99,8 +99,12 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, DKEY);
/* Pie Menu - For standard tools */
- WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", QKEY, KM_PRESS, 0, DKEY);
- WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_settings_palette", WKEY, KM_PRESS, 0, DKEY);
+ WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_tool_palette", QKEY, KM_PRESS, 0, DKEY);
+ WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_settings_palette", WKEY, KM_PRESS, 0, DKEY);
+
+ /* Add Blank Frame */
+ /* XXX: BKEY or NKEY? BKEY is easier to reach from DKEY, so we'll use that for now */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_blank_frame_add", BKEY, KM_PRESS, 0, DKEY);
/* Delete Active Frame - For easier video tutorials/review sessions */
/* NOTE: This works even when not in EditMode */
@@ -131,7 +135,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0);
/* Pie Menu - For settings/tools easy access */
- WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_sculpt", EKEY, KM_PRESS, 0, DKEY);
+ WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_sculpt", EKEY, KM_PRESS, 0, DKEY);
/* Brush Settings */
/* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys
@@ -401,6 +405,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_isolate);
WM_operatortype_append(GPENCIL_OT_layer_merge);
+ WM_operatortype_append(GPENCIL_OT_blank_frame_add);
+
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
@@ -443,6 +449,7 @@ void ED_operatortypes_gpencil(void)
/* Interpolation */
WM_operatortype_append(GPENCIL_OT_interpolate);
WM_operatortype_append(GPENCIL_OT_interpolate_sequence);
+ WM_operatortype_append(GPENCIL_OT_interpolate_reverse);
}
void ED_operatormacros_gpencil(void)
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index c23bfb1ff60..eb49060b629 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -162,6 +162,8 @@ typedef struct tGPsdata {
bGPDbrush *brush; /* current drawing brush */
short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */
int lock_axis; /* lock drawing to one axis */
+
+ short keymodifier; /* key used for invoking the operator */
} tGPsdata;
/* ------ */
@@ -484,7 +486,8 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
bGPdata *gpd = p->gpd;
bGPDbrush *brush = p->brush;
tGPspoint *pt;
-
+ ToolSettings *ts = p->scene->toolsettings;
+
/* check painting mode */
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
/* straight lines only - i.e. only store start and end point in buffer */
@@ -636,7 +639,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
View3D *v3d = p->sa->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0);
+ ED_view3d_autodist_init(p->scene, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
}
/* convert screen-coordinates to appropriate coordinates (and store them) */
@@ -756,7 +759,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
int i, totelem;
/* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
- int depth_margin = (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 4 : 0;
+ int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
/* get total number of points to allocate space for
* - drawing straight-lines only requires the endpoints
@@ -893,7 +896,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
copy_v2_v2_int(mval, &ptc->x);
if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) &&
- (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
+ (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
{
interp_depth = true;
}
@@ -910,7 +913,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
depth_arr[i] = 0.9999f;
}
else {
- if (p->gpd->flag & GP_DATA_DEPTH_STROKE_ENDPOINTS) {
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) {
/* remove all info between the valid endpoints */
int first_valid = 0;
int last_valid = 0;
@@ -1004,9 +1007,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname));
/* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head
- * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist
- * when drawing the background
- */
+ * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist
+ * when drawing the background
+ */
if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode != GP_PAINTMODE_DRAW_POLY)) {
BLI_addhead(&p->gpf->strokes, gps);
}
@@ -1623,16 +1626,24 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
* 2) Ensure that p->gpf refers to the frame used for the active layer
* (to avoid problems with other tools which expect it to exist)
*/
- bGPDlayer *gpl;
- for (gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
+ bool has_layer_to_erase = false;
+
+ for (bGPDlayer *gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
/* Skip if layer not editable */
if (gpencil_layer_is_editable(gpl) == false)
continue;
/* Add a new frame if needed (and based off the active frame,
* as we need some existing strokes to erase)
+ *
+ * Note: We don't add a new frame if there's nothing there now, so
+ * -> If there are no frames at all, don't add one
+ * -> If there are no strokes in that frame, don't add a new empty frame
*/
- gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ if (gpl->actframe && gpl->actframe->strokes.first) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ has_layer_to_erase = true;
+ }
/* XXX: we omit GP_FRAME_PAINT here for now,
* as it is only really useful for doing
@@ -1652,10 +1663,10 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
}
}
- if (p->gpf == NULL) {
+ if (has_layer_to_erase == false) {
p->status = GP_STATUS_ERROR;
//if (G.debug & G_DEBUG)
- printf("Error: No frame created (gpencil_paint_init)\n");
+ printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n");
return;
}
}
@@ -1786,6 +1797,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
static void gp_paint_strokeend(tGPsdata *p)
{
+ ToolSettings *ts = p->scene->toolsettings;
/* for surface sketching, need to set the right OpenGL context stuff so that
* the conversions will project the values correctly...
*/
@@ -1794,7 +1806,7 @@ static void gp_paint_strokeend(tGPsdata *p)
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0);
+ ED_view3d_autodist_init(p->scene, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
}
/* check if doing eraser or not */
@@ -1930,7 +1942,7 @@ static void gpencil_draw_cancel(bContext *C, wmOperator *op)
/* ------------------------------- */
-static int gpencil_draw_init(bContext *C, wmOperator *op)
+static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p;
eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
@@ -1949,6 +1961,13 @@ static int gpencil_draw_init(bContext *C, wmOperator *op)
gpencil_draw_exit(C, op);
return 0;
}
+
+ if (event != NULL) {
+ p->keymodifier = event->keymodifier;
+ }
+ else {
+ p->keymodifier = -1;
+ }
/* everything is now setup ok */
return 1;
@@ -2190,7 +2209,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
/* printf("GPencil - Starting Re-Drawing\n"); */
/* try to initialize context data needed while drawing */
- if (!gpencil_draw_init(C, op)) {
+ if (!gpencil_draw_init(C, op, NULL)) {
if (op->customdata) MEM_freeN(op->customdata);
/* printf("\tGP - no valid data\n"); */
return OPERATOR_CANCELLED;
@@ -2265,7 +2284,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
printf("GPencil - Starting Drawing\n");
/* try to initialize context data needed while drawing */
- if (!gpencil_draw_init(C, op)) {
+ if (!gpencil_draw_init(C, op, event)) {
if (op->customdata)
MEM_freeN(op->customdata);
if (G.debug & G_DEBUG)
@@ -2428,10 +2447,18 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* is essential for ensuring that they can quickly return to that view
*/
}
- else if ((ELEM(event->type, DKEY)) && (event->val == KM_RELEASE)) {
+ else if ((ELEM(event->type, p->keymodifier)) && (event->val == KM_RELEASE)) {
/* enable continuous if release D key in mid drawing */
p->scene->toolsettings->gpencil_flags |= GP_TOOL_FLAG_PAINTSESSIONS_ON;
}
+ else if ((event->type == BKEY) && (event->val == KM_RELEASE)) {
+ /* Add Blank Frame
+ * - Since this operator is non-modal, we can just call it here, and keep going...
+ * - This operator is especially useful when animating
+ */
+ WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
+ estate = OPERATOR_RUNNING_MODAL;
+ }
else {
estate = OPERATOR_RUNNING_MODAL;
}
@@ -2594,7 +2621,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
else if (p->status != GP_STATUS_ERROR) {
/* User clicked outside bounds of window while idling, so exit paintmode
- * NOTE: Don't eter this case if an error occurred while finding the
+ * NOTE: Don't enter this case if an error occurred while finding the
* region (as above)
*/
/* if drawing polygon and enable on back, must move stroke */
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 45dbde80284..2912a1ac4eb 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -1012,7 +1012,7 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
}
/* test if in lasso boundbox + within the lasso noose */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0) &&
- BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX))
+ BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX))
{
if (select) {
pt->flag |= GP_SPOINT_SELECT;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 8073b13ba10..ed05b8be9ca 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -391,7 +391,16 @@ EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C, PointerRNA
/* ******************************************************** */
/* Brush Tool Core */
-/* Check if part of stroke occurs within last segment drawn by eraser */
+/**
+ * Check whether a given stroke segment is inside a circular brush
+ *
+ * \param mval The current screen-space coordinates (midpoint) of the brush
+ * \param mvalo The previous screen-space coordinates (midpoint) of the brush (NOT CURRENTLY USED)
+ * \param rad The radius of the brush
+ *
+ * \param x0, y0 The screen-space x and y coordinates of the start of the stroke segment
+ * \param x1, y1 The screen-space x and y coordinates of the end of the stroke segment
+ */
bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
int rad, int x0, int y0, int x1, int y1)
{
@@ -502,7 +511,11 @@ bGPDpalettecolor *ED_gpencil_stroke_getcolor(bGPdata *gpd, bGPDstroke *gps)
/* ******************************************************** */
/* Space Conversion */
-/* Init handling for space-conversion function (from passed-in parameters) */
+/**
+ * Init settings for stroke point space conversions
+ *
+ * \param r_gsc: [out] The space conversion settings struct, populated with necessary params
+ */
void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
{
ScrArea *sa = CTX_wm_area(C);
@@ -538,7 +551,13 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
}
}
-/* convert point to parent space */
+/**
+ * Convert point to parent space
+ *
+ * \param pt Original point
+ * \param diff_mat Matrix with the difference between original parent matrix
+ * \param[out] r_pt Pointer to new point after apply matrix
+ */
void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt)
{
float fpt[3];
@@ -547,7 +566,9 @@ void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *
copy_v3_v3(&r_pt->x, fpt);
}
-/* Change position relative to parent object */
+/**
+ * Change points position relative to parent object
+ */
void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt;
@@ -568,7 +589,9 @@ void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
}
}
-/* Change point position relative to parent object */
+/**
+ * Change point position relative to parent object
+ */
void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt)
{
/* undo matrix */
@@ -583,8 +606,13 @@ void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt)
copy_v3_v3(&pt->x, fpt);
}
-/* Convert Grease Pencil points to screen-space values
- * WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn
+/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
+ *
+ * \param[out] r_x The screen-space x-coordinate of the point
+ * \param[out] r_y The screen-space y-coordinate of the point
+ *
+ * \warning This assumes that the caller has already checked whether the stroke in question can be drawn.
*/
void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
int *r_x, int *r_y)
@@ -628,8 +656,16 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
}
}
-/* Convert Grease Pencil points to screen-space values (as floats)
- * WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn
+/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
+ *
+ * Just like gp_point_to_xy(), except the resulting coordinates are floats not ints.
+ * Use this version to solve "stair-step" artifacts which may arise when roundtripping the calculations.
+ *
+ * \param r_x: [out] The screen-space x-coordinate of the point
+ * \param r_y: [out] The screen-space y-coordinate of the point
+ *
+ * \warning This assumes that the caller has already checked whether the stroke in question can be drawn
*/
void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
float *r_x, float *r_y)
@@ -688,6 +724,12 @@ void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
/**
* Project screenspace coordinates to 3D-space
*
+ * For use with editing tools where it is easier to perform the operations in 2D,
+ * and then later convert the transformed points back to 3D.
+ *
+ * \param screen_co: The screenspace 2D coordinates to convert to
+ * \param r_out: The resulting 3D coordinates of the input point
+ *
* \note We include this as a utility function, since the standard method
* involves quite a few steps, which are invariably always the same
* for all GPencil operations. So, it's nicer to just centralize these.
@@ -722,7 +764,7 @@ bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, Scene *scene, const float screen
}
/**
- * Apply smooth to stroke point
+ * Apply smooth to stroke point
* \param gps Stroke to smooth
* \param i Point index
* \param inf Amount of smoothing to apply
@@ -830,8 +872,8 @@ bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf)
ptc = &gps->points[after];
/* the optimal value is the corresponding to the interpolation of the strength
- * at the distance of point b
- */
+ * at the distance of point b
+ */
const float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
@@ -915,7 +957,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
/**
* Add randomness to stroke
* \param gps Stroke data
- * \param brsuh Brush data
+ * \param brush Brush data
*/
void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush)
{
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 4a4ab832b28..68a5dd8a94e 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -124,6 +124,15 @@ typedef struct bAnimListElem {
void *key_data; /* motion data - mostly F-Curves, but can be other types too */
+ /* NOTE: id here is the "IdAdtTemplate"-style datablock (e.g. Object, Material, Texture, NodeTree)
+ * from which evaluation of the RNA-paths takes place. It's used to figure out how deep
+ * channels should be nested (e.g. for Textures/NodeTrees) in the tree, and allows property
+ * lookups (e.g. for sliders and for inserting keyframes) to work. If we had instead used
+ * bAction or something similar, none of this would be possible: although it's trivial
+ * to use an IdAdtTemplate type to find the source action a channel (e.g. F-Curve) comes from
+ * (i.e. in the AnimEditors, it *must* be the active action, as only that can be edited),
+ * it's impossible to go the other way (i.e. one action may be used in multiple places).
+ */
struct ID *id; /* ID block that channel is attached to */
struct AnimData *adt; /* source of the animation data attached to ID block (for convenience) */
@@ -256,7 +265,7 @@ typedef enum eAnimFilter_Flags {
ANIMFILTER_TMP_PEEK = (1 << 30),
/* ignore ONLYSEL flag from filterflag, (internal use only!) */
- ANIMFILTER_TMP_IGNORE_ONLYSEL = (1 << 31)
+ ANIMFILTER_TMP_IGNORE_ONLYSEL = (1u << 31)
} eAnimFilter_Flags;
/* ---------- Flag Checking Macros ------------ */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 904132b8876..9130336228d 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -130,8 +130,9 @@ void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
void ED_armature_deselect_all(struct Object *obedit);
void ED_armature_deselect_all_visible(struct Object *obedit);
-int ED_do_pose_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer,
- short hits, bool extend, bool deselect, bool toggle, bool do_nearest);
+bool ED_do_pose_selectbuffer(
+ struct Scene *scene, struct Base *base, const unsigned int *buffer, short hits,
+ bool extend, bool deselect, bool toggle, bool do_nearest);
bool ED_armature_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
int join_armature_exec(struct bContext *C, struct wmOperator *op);
struct Bone *get_indexed_bone(struct Object *ob, int index);
@@ -157,9 +158,9 @@ void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]);
void transform_armature_mirror_update(struct Object *obedit);
void ED_armature_origin_set(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around);
-void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]);
-void ED_armature_apply_transform(struct Object *ob, float mat[4][4]);
-void ED_armature_transform(struct bArmature *arm, float mat[4][4]);
+void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props);
+void ED_armature_apply_transform(struct Object *ob, float mat[4][4], const bool do_props);
+void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props);
#define ARM_GROUPS_NAME 1
#define ARM_GROUPS_ENVELOPE 2
@@ -171,6 +172,7 @@ void create_vgroups_from_armature(struct ReportList *reports, struct Scene *scen
/* if bone is already in list, pass it as param to ignore it */
void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone);
void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep);
+void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names);
void undo_push_armature(struct bContext *C, const char *name);
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 5f8ebd87d19..91f8b39f7b9 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -63,7 +63,7 @@ int ED_space_clip_get_clip_frame_number(struct SpaceClip *sc);
struct ImBuf *ED_space_clip_get_buffer(struct SpaceClip *sc);
struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc, float loc[2], float *scale, float *angle);
-bool ED_space_clip_color_sample(struct Scene *scene, struct SpaceClip *sc, struct ARegion *ar, int mval[2], float r_col[3]);
+bool ED_space_clip_color_sample(struct SpaceClip *sc, struct ARegion *ar, int mval[2], float r_col[3]);
void ED_clip_update_frame(const struct Main *mainp, int cfra);
bool ED_clip_view_selection(const struct bContext *C, struct ARegion *ar, bool fit);
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 283113f93d6..9de550a20ce 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -46,7 +46,7 @@ void ED_space_image_set(struct SpaceImage *sima, struct Scene *scene, s
struct Mask *ED_space_image_get_mask(struct SpaceImage *sima);
void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
-bool ED_space_image_color_sample(struct Scene *scene, struct SpaceImage *sima, struct ARegion *ar, int mval[2], float r_col[3]);
+bool ED_space_image_color_sample(struct SpaceImage *sima, struct ARegion *ar, int mval[2], float r_col[3]);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock);
void ED_space_image_release_buffer(struct SpaceImage *sima, struct ImBuf *ibuf, void *lock);
bool ED_space_image_has_buffer(struct SpaceImage *sima);
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index de798b1fce2..c867df2d01a 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -282,6 +282,7 @@ bool ED_mesh_uv_texture_remove_active(struct Mesh *me);
bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name);
void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me);
void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum);
+bool ED_mesh_color_ensure(struct Mesh *me, const char *name);
int ED_mesh_color_add(struct Mesh *me, const char *name, const bool active_set);
bool ED_mesh_color_remove_index(struct Mesh *me, const int n);
bool ED_mesh_color_remove_active(struct Mesh *me);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index f7b9d6b4f9e..e3c382382a9 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -107,7 +107,7 @@ void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree,
void ED_operatormacros_node(void);
/* node_view.c */
-bool ED_space_node_color_sample(struct Scene *scene, struct SpaceNode *snode, struct ARegion *ar, int mval[2], float r_col[3]);
+bool ED_space_node_color_sample(struct SpaceNode *snode, struct ARegion *ar, int mval[2], float r_col[3]);
#endif /* __ED_NODE_H__ */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index ec09add56b8..4253e214537 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -107,7 +107,7 @@ bool ED_screen_set(struct bContext *C, struct bScreen *sc);
bool ED_screen_delete(struct bContext *C, struct bScreen *sc);
void ED_screen_set_scene(struct bContext *C, struct bScreen *screen, struct Scene *scene);
bool ED_screen_delete_scene(struct bContext *C, struct Scene *scene);
-void ED_screen_set_subwinactive(struct bContext *C, struct wmEvent *event);
+void ED_screen_set_subwinactive(struct bContext *C, const struct wmEvent *event);
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen);
void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh, int sync, int enable);
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index ebd2a3dcb7a..9a0a7f8f1bb 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -148,7 +148,8 @@ int BIF_countTransformOrientation(const struct bContext *C);
#define P_CORRECT_UV (1 << 8)
#define P_NO_DEFAULTS (1 << 10)
#define P_NO_TEXSPACE (1 << 11)
-#define P_GPENCIL_EDIT (1 << 12)
+#define P_CENTER (1 << 12)
+#define P_GPENCIL_EDIT (1 << 13)
void Transform_Properties(struct wmOperatorType *ot, int flags);
@@ -159,12 +160,6 @@ void BIF_draw_manipulator(const struct bContext *C);
/* Snapping */
-typedef enum SnapSelect {
- SNAP_ALL = 0,
- SNAP_NOT_SELECTED = 1,
- SNAP_NOT_ACTIVE = 2,
-} SnapSelect;
-
#define SNAP_MIN_DISTANCE 30
bool peelObjectsTransform(
@@ -187,11 +182,7 @@ bool snapObjectsTransform(
/* return args */
float r_loc[3], float r_no[3]);
bool snapNodesTransform(
- struct TransInfo *t, const int mval[2], SnapSelect snap_select,
- /* return args */
- float r_loc[2], float *r_dist_px, char *r_node_border);
-bool snapNodesContext(
- struct bContext *C, const int mval[2], SnapSelect snap_select,
+ struct TransInfo *t, const int mval[2],
/* return args */
float r_loc[2], float *r_dist_px, char *r_node_border);
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 7944b434057..e440e8c8389 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -40,6 +40,12 @@ struct View3D;
/* ED_transform_snap_object_*** API */
+typedef enum SnapSelect {
+ SNAP_ALL = 0,
+ SNAP_NOT_SELECTED = 1,
+ SNAP_NOT_ACTIVE = 2,
+} SnapSelect;
+
/** used for storing multiple hits */
struct SnapObjectHitDepth {
struct SnapObjectHitDepth *next, *prev;
@@ -65,10 +71,6 @@ struct SnapObjectParams {
unsigned int use_object_edit_cage : 1;
};
-enum {
- SNAP_OBJECT_USE_CACHE = (1 << 0),
-};
-
typedef struct SnapObjectContext SnapObjectContext;
SnapObjectContext *ED_transform_snap_object_context_create(
struct Main *bmain, struct Scene *scene, int flag);
@@ -88,7 +90,6 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
bool ED_transform_snap_object_project_ray_ex(
struct SnapObjectContext *sctx,
- const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
/* return args */
@@ -102,7 +103,6 @@ bool ED_transform_snap_object_project_ray(
bool ED_transform_snap_object_project_ray_all(
SnapObjectContext *sctx,
- const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float ray_depth, bool sort,
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index a4afa958450..60c4b3593aa 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -60,6 +60,7 @@ void ED_undo_redo(struct bContext *C);
void ED_OT_undo(struct wmOperatorType *ot);
void ED_OT_undo_push(struct wmOperatorType *ot);
void ED_OT_redo(struct wmOperatorType *ot);
+void ED_OT_undo_redo(struct wmOperatorType *ot);
void ED_OT_undo_history(struct wmOperatorType *ot);
int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 48c1e2d1996..85fb0ee4447 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -47,6 +47,7 @@ struct Main;
struct MetaElem;
struct Nurb;
struct Object;
+struct RV3DMatrixStore;
struct RegionView3D;
struct Scene;
struct ScrArea;
@@ -105,7 +106,14 @@ void ED_view3d_lastview_store(struct RegionView3D *rv3d);
/* Depth buffer */
void ED_view3d_depth_update(struct ARegion *ar);
-float ED_view3d_depth_read_cached(const struct ViewContext *vc, int x, int y);
+float ED_view3d_depth_read_cached(const struct ViewContext *vc, const int mval[2]);
+bool ED_view3d_depth_read_cached_normal(
+ const ViewContext *vc, const struct bglMats *mats, const int mval[2],
+ float r_normal[3]);
+bool ED_view3d_depth_unproject(
+ const struct ARegion *ar, const struct bglMats *mats,
+ const int mval[2], const double depth,
+ float r_location_world[3]);
void ED_view3d_depth_tag_update(struct RegionView3D *rv3d);
/* Projection */
@@ -216,8 +224,14 @@ 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]);
+void ED_view3d_win_to_3d(
+ const struct View3D *v3d, const struct ARegion *ar,
+ const float depth_pt[3], const float mval[2],
+ float r_out[3]);
+void ED_view3d_win_to_3d_int(
+ const struct View3D *v3d, const struct ARegion *ar,
+ const float depth_pt[3], const int mval[2],
+ float r_out[3]);
void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac);
void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]);
void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]);
@@ -295,7 +309,22 @@ bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], con
/* select */
#define MAXPICKELEMS 2500
#define MAXPICKBUF (4 * MAXPICKELEMS)
-short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input, bool do_nearest);
+
+typedef enum {
+ /* all elements in the region, ignore depth */
+ VIEW3D_SELECT_ALL = 0,
+ /* pick also depth sorts (only for small regions!) */
+ VIEW3D_SELECT_PICK_ALL = 1,
+ /* sorts and only returns visible objects (only for small regions!) */
+ VIEW3D_SELECT_PICK_NEAREST = 2,
+} eV3DSelectMode;
+
+void view3d_opengl_select_cache_begin(void);
+void view3d_opengl_select_cache_end(void);
+
+int view3d_opengl_select(
+ struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input,
+ eV3DSelectMode select_mode);
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
@@ -324,8 +353,8 @@ void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d);
#endif
int ED_view3d_scene_layer_set(int lay, const int *values, int *active);
-void *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d);
-void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, void *rv3dmat_pt);
+struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d);
+void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat);
bool ED_view3d_context_activate(struct bContext *C);
void ED_view3d_draw_offscreen_init(struct Scene *scene, struct View3D *v3d);
@@ -334,6 +363,9 @@ void ED_view3d_draw_offscreen(
float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, const char *viewname,
struct GPUFX *fx, struct GPUFXSettings *fx_settings,
struct GPUOffScreen *ofs);
+void ED_view3d_draw_setup_view(
+ struct wmWindow *win, struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
+ float viewmat[4][4], float winmat[4][4], const struct rcti *rect);
struct ImBuf *ED_view3d_draw_offscreen_imbuf(
struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey,
@@ -348,7 +380,9 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip);
-void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]);
+void ED_view3d_update_viewmat(
+ struct Scene *scene, struct View3D *v3d, struct ARegion *ar,
+ float viewmat[4][4], float winmat[4][4], const struct rcti *rect);
bool ED_view3d_quat_from_axis_view(const char view, float quat[4]);
char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon);
char ED_view3d_lock_view_from_index(int index);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index e016e014a1a..0c83038b7a3 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -313,9 +313,9 @@ DEF_ICON(OUTLINER_OB_ARMATURE)
DEF_ICON(OUTLINER_OB_FONT)
DEF_ICON(OUTLINER_OB_SURFACE)
DEF_ICON(OUTLINER_OB_SPEAKER)
+DEF_ICON(OUTLINER_OB_FORCE_FIELD)
+DEF_ICON(OUTLINER_OB_GROUP_INSTANCE)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK120)
- DEF_ICON(BLANK121)
DEF_ICON(BLANK122)
DEF_ICON(BLANK123)
DEF_ICON(BLANK124)
@@ -653,9 +653,9 @@ DEF_ICON(IPO_BACK)
DEF_ICON(IPO_EASE_IN)
DEF_ICON(IPO_EASE_OUT)
DEF_ICON(IPO_EASE_IN_OUT)
+DEF_ICON(NORMALIZE_FCURVES)
#ifndef DEF_ICON_BLANK_SKIP
/* available */
- DEF_ICON(BLANK203)
DEF_ICON(BLANK204)
DEF_ICON(BLANK205)
DEF_ICON(BLANK206)
@@ -1005,15 +1005,6 @@ DEF_ICON(MATCAP_23)
DEF_ICON(MATCAP_24)
/* vector icons, VICO_ prefix added */
-DEF_VICO(VIEW3D_VEC)
-DEF_VICO(EDIT_VEC)
-DEF_VICO(EDITMODE_VEC_DEHLT)
-DEF_VICO(EDITMODE_VEC_HLT)
-DEF_VICO(DISCLOSURE_TRI_RIGHT_VEC)
-DEF_VICO(DISCLOSURE_TRI_DOWN_VEC)
-DEF_VICO(MOVE_UP_VEC)
-DEF_VICO(MOVE_DOWN_VEC)
-DEF_VICO(X_VEC)
DEF_VICO(SMALL_TRI_RIGHT_VEC)
DEF_VICO(KEYTYPE_KEYFRAME_VEC)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index fd5351394c3..890fe720991 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -181,7 +181,7 @@ enum {
UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */
UI_BUT_UPDATE_DELAY = (1 << 28), /* don't run updates while dragging (needed in rare cases). */
UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */
- UI_BUT_SEARCH_UNLINK = (1 << 30), /* show unlink for search button */
+ UI_BUT_VALUE_CLEAR = (1 << 30), /* show 'x' icon to clear/unlink value of text or search button */
};
#define UI_PANEL_WIDTH 340
@@ -212,12 +212,13 @@ enum {
UI_BUT_ALIGN_STITCH_TOP = (1 << 18),
UI_BUT_ALIGN_STITCH_LEFT = (1 << 19),
UI_BUT_ALIGN_ALL = (UI_BUT_ALIGN | UI_BUT_ALIGN_STITCH_TOP | UI_BUT_ALIGN_STITCH_LEFT),
+
+ UI_BUT_BOX_ITEM = (1 << 20), /* This but is "inside" a box item (currently used to change theme colors). */
};
/* scale fixed button widths by this to account for DPI */
#define UI_DPI_FAC ((U.pixelsize * (float)U.dpi) / 72.0f)
-#define UI_DPI_WINDOW_FAC (((float)U.dpi) / 72.0f)
/* 16 to copy ICON_DEFAULT_HEIGHT */
#define UI_DPI_ICON_SIZE ((float)16 * UI_DPI_FAC)
@@ -421,7 +422,7 @@ typedef void (*uiBlockCancelFunc)(struct bContext *C, void *arg1);
void UI_popup_block_invoke(struct bContext *C, uiBlockCreateFunc func, void *arg);
void UI_popup_block_invoke_ex(struct bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext);
-void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg);
+void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg, struct wmOperator *op);
/* void uiPupBlockOperator(struct bContext *C, uiBlockCreateFunc func, struct wmOperator *op, int opcontext); */ /* UNUSED */
void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block);
@@ -438,7 +439,7 @@ void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *blo
* */
uiBlock *UI_block_begin(const struct bContext *C, struct ARegion *region, const char *name, short dt);
-void UI_block_end_ex(const struct bContext *C, uiBlock *block, const int xy[2]);
+void UI_block_end_ex(const struct bContext *C, uiBlock *block, const int xy[2], int r_xy[2]);
void UI_block_end(const struct bContext *C, uiBlock *block);
void UI_block_draw(const struct bContext *C, struct uiBlock *block);
void UI_block_update_from_old(const struct bContext *C, struct uiBlock *block);
@@ -995,7 +996,7 @@ void uiItemsFullEnumO(
struct IDProperty *properties, int context, int flag);
void uiItemsFullEnumO_items(
uiLayout *layout, struct wmOperatorType *ot, PointerRNA ptr, PropertyRNA *prop,
- IDProperty *properties, int context, int flag,
+ struct IDProperty *properties, int context, int flag,
const EnumPropertyItem *item_array, int totitem);
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
@@ -1083,7 +1084,7 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
/* Float precision helpers */
-#define UI_PRECISION_FLOAT_MAX 7
+#define UI_PRECISION_FLOAT_MAX 6
/* For float buttons the 'step' (or a1), is scaled */
#define UI_PRECISION_FLOAT_SCALE 0.01f
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index f8a5f30a596..a0efd586af5 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -303,7 +303,6 @@ enum {
TH_EDGE_BEVEL,
TH_VERTEX_BEVEL
};
-/* XXX WARNING: previous is saved in file, so do not change order! */
/* specific defines per space should have higher define values */
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 4caacb65f5f..4c0493a881c 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -203,6 +203,7 @@ bool UI_view2d_view_to_region_clip(struct View2D *v2d, float x, float y, int *r
void UI_view2d_view_to_region(struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
void UI_view2d_view_to_region_fl(struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL();
+void UI_view2d_view_to_region_m4(struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL();
void UI_view2d_view_to_region_rcti(struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL();
bool UI_view2d_view_to_region_rcti_clip(struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL();
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 6bba35e821f..30e47bc3d9e 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -366,10 +366,10 @@ static void ui_block_bounds_calc_centered_pie(uiBlock *block)
static void ui_block_bounds_calc_popup(
wmWindow *window, uiBlock *block,
- eBlockBoundsCalc bounds_calc, const int xy[2])
+ eBlockBoundsCalc bounds_calc, const int xy[2], int r_xy[2])
{
int width, height, oldwidth, oldheight;
- int oldbounds, xmax, ymax;
+ int oldbounds, xmax, ymax, raw_x, raw_y;
const int margin = UI_SCREEN_MARGIN;
rcti rect, rect_bounds;
int ofs_dummy[2];
@@ -407,8 +407,8 @@ static void ui_block_bounds_calc_popup(
/* offset block based on mouse position, user offset is scaled
* along in case we resized the block in ui_block_bounds_calc_text */
- rect.xmin = xy[0] + block->rect.xmin + (block->mx * width) / oldwidth;
- rect.ymin = xy[1] + block->rect.ymin + (block->my * height) / oldheight;
+ raw_x = rect.xmin = xy[0] + block->rect.xmin + (block->mx * width) / oldwidth;
+ raw_y = rect.ymin = xy[1] + block->rect.ymin + (block->my * height) / oldheight;
rect.xmax = rect.xmin + width;
rect.ymax = rect.ymin + height;
@@ -422,6 +422,13 @@ static void ui_block_bounds_calc_popup(
/* now recompute bounds and safety */
ui_block_bounds_calc(block);
+
+ /* If given, adjust input coordinates such that they would generate real final popup position.
+ * Needed to handle correctly floating panels once they have been dragged around, see T52999. */
+ if (r_xy) {
+ r_xy[0] = xy[0] + block->rect.xmin - raw_x;
+ r_xy[1] = xy[1] + block->rect.ymin - raw_y;
+ }
}
/* used for various cases */
@@ -488,6 +495,9 @@ static int ui_but_calc_float_precision(uiBut *but, double value)
else if (prec == -1) {
prec = (but->hardmax < 10.001f) ? 3 : 2;
}
+ else {
+ CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX);
+ }
return UI_calc_float_precision(prec, value);
}
@@ -684,7 +694,7 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu
if (oldbut->active) {
/* flags from the buttons we want to refresh, may want to add more here... */
- const int flag_copy = UI_BUT_REDALERT;
+ const int flag_copy = UI_BUT_REDALERT | UI_HAS_ICON;
found_active = true;
@@ -1165,6 +1175,8 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
uiBut *but;
char buf[128];
+ BLI_assert(block->flag & UI_BLOCK_LOOP);
+
/* only do it before bounding */
if (block->rect.xmin != block->rect.xmax)
return;
@@ -1179,6 +1191,9 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
}
else {
for (but = block->buttons.first; but; but = but->next) {
+ if (but->dt != UI_EMBOSS_PULLDOWN) {
+ continue;
+ }
if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) {
ui_but_add_shortcut(but, buf, false);
@@ -1223,7 +1238,7 @@ void UI_block_update_from_old(const bContext *C, uiBlock *block)
block->oldblock = NULL;
}
-void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2])
+void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_xy[2])
{
wmWindow *window = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
@@ -1291,7 +1306,7 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2])
/* fallback */
case UI_BLOCK_BOUNDS_POPUP_MOUSE:
case UI_BLOCK_BOUNDS_POPUP_MENU:
- ui_block_bounds_calc_popup(window, block, block->bounds_type, xy);
+ ui_block_bounds_calc_popup(window, block, block->bounds_type, xy, r_xy);
break;
}
@@ -1309,7 +1324,7 @@ void UI_block_end(const bContext *C, uiBlock *block)
{
wmWindow *window = CTX_wm_window(C);
- UI_block_end_ex(C, block, &window->eventstate->x);
+ UI_block_end_ex(C, block, &window->eventstate->x, NULL);
}
/* ************** BLOCK DRAWING FUNCTION ************* */
@@ -1337,7 +1352,7 @@ static void ui_but_to_pixelrect(rcti *rect, const ARegion *ar, uiBlock *block, u
rctf rectf;
ui_block_to_window_rctf(ar, block, &rectf, (but) ? &but->rect : &block->rect);
- BLI_rcti_rctf_copy_floor(rect, &rectf);
+ BLI_rcti_rctf_copy_round(rect, &rectf);
BLI_rcti_translate(rect, -ar->winrct.xmin, -ar->winrct.ymin);
}
@@ -1932,13 +1947,14 @@ void ui_but_value_set(uiBut *but, double value)
else {
/* first do rounding */
if (but->pointype == UI_BUT_POIN_CHAR) {
- value = (char)floor(value + 0.5);
+ value = round_db_to_uchar_clamp(value);
}
else if (but->pointype == UI_BUT_POIN_SHORT) {
- value = (short)floor(value + 0.5);
+ value = round_db_to_short_clamp(value);
+ }
+ else if (but->pointype == UI_BUT_POIN_INT) {
+ value = round_db_to_int_clamp(value);
}
- else if (but->pointype == UI_BUT_POIN_INT)
- value = (int)floor(value + 0.5);
else if (but->pointype == UI_BUT_POIN_FLOAT) {
float fval = (float)value;
if (fval >= -0.00001f && fval <= 0.00001f) fval = 0.0f; /* prevent negative zero */
@@ -1987,22 +2003,29 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but)
/** \name Check to show extra icons
*
* Extra icons are shown on the right hand side of buttons.
+ * This could (should!) definitely become more generic, but for now this is good enough.
* \{ */
+static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
+{
+ BLI_assert(but->type == UI_BTYPE_TEXT);
+ return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr[0]);
+}
+
static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
{
BLI_assert(but->type == UI_BTYPE_SEARCH_MENU);
return ((but->editstr == NULL) &&
(but->drawstr[0] != '\0') &&
- (but->flag & UI_BUT_SEARCH_UNLINK));
+ (but->flag & UI_BUT_VALUE_CLEAR));
}
-static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but)
+static bool ui_but_icon_extra_is_visible_search_eyedropper(uiBut *but)
{
StructRNA *type;
short idcode;
- BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_SEARCH_UNLINK));
+ BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_VALUE_CLEAR));
if (but->rnaprop == NULL) {
return false;
@@ -2011,21 +2034,31 @@ static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but)
type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
idcode = RNA_type_to_ID_code(type);
-
return ((but->editstr == NULL) &&
(idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode)));
}
uiButExtraIconType ui_but_icon_extra_get(uiBut *but)
{
- if ((but->flag & UI_BUT_SEARCH_UNLINK) == 0) {
- /* pass */
- }
- else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
- return UI_BUT_ICONEXTRA_UNLINK;
- }
- else if (ui_but_icon_extra_is_visible_eyedropper(but)) {
- return UI_BUT_ICONEXTRA_EYEDROPPER;
+ switch (but->type) {
+ case UI_BTYPE_TEXT:
+ if (ui_but_icon_extra_is_visible_text_clear(but)) {
+ return UI_BUT_ICONEXTRA_CLEAR;
+ }
+ break;
+ case UI_BTYPE_SEARCH_MENU:
+ if ((but->flag & UI_BUT_VALUE_CLEAR) == 0) {
+ /* pass */
+ }
+ else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
+ return UI_BUT_ICONEXTRA_CLEAR;
+ }
+ else if (ui_but_icon_extra_is_visible_search_eyedropper(but)) {
+ return UI_BUT_ICONEXTRA_EYEDROPPER;
+ }
+ break;
+ default:
+ break;
}
return UI_BUT_ICONEXTRA_NONE;
@@ -2129,9 +2162,14 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
/**
* \param float_precision For number buttons the precision to use or -1 to fallback to the button default.
+ * \param use_exp_float Use exponent representation of floats when out of reasonable range (outside of 1e3/1e-3).
*/
-void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision)
+void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision, const bool use_exp_float, bool *r_use_exp_float)
{
+ if (r_use_exp_float) {
+ *r_use_exp_float = false;
+ }
+
if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
PropertyType type;
const char *buf = NULL;
@@ -2199,17 +2237,38 @@ void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int
ui_get_but_string_unit(but, str, maxlen, value, false, float_precision);
}
else {
- const int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) : float_precision;
- BLI_snprintf(str, maxlen, "%.*f", prec, value);
+ int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) : float_precision;
+ if (use_exp_float) {
+ const int int_digits_num = integer_digits_f(value);
+ if (int_digits_num < -6 || int_digits_num > 12) {
+ BLI_snprintf(str, maxlen, "%.*g", prec, value);
+ if (r_use_exp_float) {
+ *r_use_exp_float = true;
+ }
+ }
+ else {
+ prec -= int_digits_num;
+ CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX);
+ BLI_snprintf(str, maxlen, "%.*f", prec, value);
+ }
+ }
+ else {
+#if 0 /* TODO, but will likely break some stuff, so better after 2.79 release. */
+ prec -= int_digits_num;
+ CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX);
+#endif
+ BLI_snprintf(str, maxlen, "%.*f", prec, value);
+ }
}
}
- else
+ else {
BLI_snprintf(str, maxlen, "%d", (int)value);
+ }
}
}
void ui_but_string_get(uiBut *but, char *str, const size_t maxlen)
{
- ui_but_string_get_ex(but, str, maxlen, -1);
+ ui_but_string_get_ex(but, str, maxlen, -1, false, NULL);
}
/**
@@ -2271,7 +2330,7 @@ char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size)
#ifdef WITH_PYTHON
-static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char *str, double *value)
+static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char *str, double *r_value)
{
char str_unit_convert[256];
const int unit_type = UI_but_unit_type_get(but);
@@ -2283,13 +2342,13 @@ static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char
bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), but->drawstr,
ui_get_but_scale_unit(but, 1.0), but->block->unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type));
- return BPY_execute_string_as_number(C, str_unit_convert, value, true);
+ return BPY_execute_string_as_number(C, str_unit_convert, true, r_value);
}
#endif /* WITH_PYTHON */
-bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double *value)
+bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double *r_value)
{
bool ok = false;
@@ -2298,13 +2357,13 @@ bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double
if (str[0] != '\0') {
bool is_unit_but = (ui_but_is_float(but) && ui_but_is_unit(but));
/* only enable verbose if we won't run again with units */
- if (BPY_execute_string_as_number(C, str, value, is_unit_but == false)) {
+ if (BPY_execute_string_as_number(C, str, is_unit_but == false, r_value)) {
/* if the value parsed ok without unit conversion this button may still need a unit multiplier */
if (is_unit_but) {
char str_new[128];
- BLI_snprintf(str_new, sizeof(str_new), "%f", *value);
- ok = ui_set_but_string_eval_num_unit(C, but, str_new, value);
+ BLI_snprintf(str_new, sizeof(str_new), "%f", *r_value);
+ ok = ui_set_but_string_eval_num_unit(C, but, str_new, r_value);
}
else {
ok = true; /* parse normal string via py (no unit conversion needed) */
@@ -2312,17 +2371,16 @@ bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double
}
else if (is_unit_but) {
/* parse failed, this is a unit but so run replacements and parse again */
- ok = ui_set_but_string_eval_num_unit(C, but, str, value);
+ ok = ui_set_but_string_eval_num_unit(C, but, str, r_value);
}
}
#else /* WITH_PYTHON */
- *value = atof(str);
+ *r_value = atof(str);
ok = true;
- (void)C;
- (void)but;
+ UNUSED_VARS(C, but);
#endif /* WITH_PYTHON */
@@ -2432,7 +2490,9 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
return false;
}
- if (!ui_but_is_float(but)) value = (int)floor(value + 0.5);
+ if (!ui_but_is_float(but)) {
+ value = floor(value + 0.5);
+ }
/* not that we use hard limits here */
if (value < (double)but->hardmin) value = but->hardmin;
@@ -3151,7 +3211,9 @@ static uiBut *ui_def_but(
}
if (block->flag & UI_BLOCK_RADIAL) {
- but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
+ but->drawflag |= UI_BUT_TEXT_LEFT;
+ if (but->str && but->str[0])
+ but->drawflag |= UI_BUT_ICON_LEFT;
}
else if ((block->flag & UI_BLOCK_LOOP) ||
ELEM(but->type,
@@ -3896,6 +3958,8 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block, int type, wmOperatorType *ot, int o
uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, int opcontext, int icon, const char *str, int x, int y, short width, short height, const char *tip)
{
wmOperatorType *ot = WM_operatortype_find(opname, 0);
+ if (str && str[0] == '\0')
+ return uiDefIconButO_ptr(block, type, ot, opcontext, icon, x, y, width, height, tip);
return uiDefIconTextButO_ptr(block, type, ot, opcontext, icon, str, x, y, width, height, tip);
}
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 5da294302e9..a04360b3395 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -39,6 +39,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_nla.h"
@@ -210,6 +211,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
/* updates */
driver->flag |= DRIVER_FLAG_RECOMPILE;
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL);
ok = true;
}
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index d7f06b7db13..eab609ebe84 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -225,7 +225,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
return false;
}
- if (RNA_property_subtype(eye->prop) == PROP_COLOR) {
+ if (RNA_property_subtype(eye->prop) != PROP_COLOR) {
const char *display_device;
float col[4];
@@ -235,7 +235,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
/* store inital color */
RNA_property_float_get_array(&eye->ptr, eye->prop, col);
if (eye->display) {
- IMB_colormanagement_scene_linear_to_display_v3(col, eye->display);
+ IMB_colormanagement_display_to_scene_linear_v3(col, eye->display);
}
copy_v3_v3(eye->init_col, col);
}
@@ -266,6 +266,8 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
/* we could use some clever */
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my);
+ const char *display_device = CTX_data_scene(C)->display_settings.display_device;
+ struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
if (sa) {
if (sa->spacetype == SPACE_IMAGE) {
@@ -275,7 +277,7 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
- if (ED_space_image_color_sample(CTX_data_scene(C), sima, ar, mval, r_col)) {
+ if (ED_space_image_color_sample(sima, ar, mval, r_col)) {
return;
}
}
@@ -287,7 +289,7 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
- if (ED_space_node_color_sample(CTX_data_scene(C), snode, ar, mval, r_col)) {
+ if (ED_space_node_color_sample(snode, ar, mval, r_col)) {
return;
}
}
@@ -299,7 +301,7 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
- if (ED_space_clip_color_sample(CTX_data_scene(C), sc, ar, mval, r_col)) {
+ if (ED_space_clip_color_sample(sc, ar, mval, r_col)) {
return;
}
}
@@ -310,6 +312,8 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
glReadBuffer(GL_FRONT);
glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
glReadBuffer(GL_BACK);
+
+ IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
}
/* sets the sample color RGB, maintaining A */
@@ -320,10 +324,10 @@ static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3
/* to maintain alpha */
RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv);
- /* convert from display space to linear rgb space */
+ /* convert from linear rgb space to display space */
if (eye->display) {
copy_v3_v3(col_conv, col);
- IMB_colormanagement_display_to_scene_linear_v3(col_conv, eye->display);
+ IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
}
else {
copy_v3_v3(col_conv, col);
@@ -748,7 +752,7 @@ static int datadropper_poll(bContext *C)
if ((CTX_wm_window(C) != NULL) &&
(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
(but->type == UI_BTYPE_SEARCH_MENU) &&
- (but->flag & UI_BUT_SEARCH_UNLINK))
+ (but->flag & UI_BUT_VALUE_CLEAR))
{
if (prop && RNA_property_type(prop) == PROP_POINTER) {
StructRNA *type = RNA_property_pointer_type(&ptr, prop);
@@ -882,7 +886,6 @@ static void depthdropper_exit(bContext *C, wmOperator *op)
*/
static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth)
{
-
/* we could use some clever */
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my);
@@ -923,7 +926,7 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx,
float co_align[3];
/* quick way to get view-center aligned point */
- ED_view3d_win_to_3d(ar, co, mval_center_fl, co_align);
+ ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align);
*r_depth = len_v3v3(view_co, co_align);
@@ -1083,7 +1086,7 @@ static int depthdropper_poll(bContext *C)
return 1;
}
}
- else {
+ else {
RegionView3D *rv3d = CTX_wm_region_view3d(C);
if (rv3d && rv3d->persp == RV3D_CAMOB) {
View3D *v3d = CTX_wm_view3d(C);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index fc511d61e2b..f7dfb4b7fd2 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -50,6 +50,7 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_linklist.h"
+#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_string_cursor_utf8.h"
@@ -86,6 +87,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "wm_event_system.h"
#ifdef WITH_INPUT_IME
# include "wm_window.h"
@@ -379,6 +381,7 @@ typedef struct uiAfterFunc {
void *butm_func_arg;
int a2;
+ wmOperator *popup_op;
wmOperatorType *optype;
int opcontext;
PointerRNA *opptr;
@@ -634,13 +637,24 @@ PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext,
return ptr;
}
+static void popup_check(bContext *C, wmOperator *op)
+{
+ if (op && op->type->check && op->type->check(C, op)) {
+ /* check for popup and re-layout buttons */
+ ARegion *ar_menu = CTX_wm_menu(C);
+ if (ar_menu)
+ ED_region_tag_refresh_ui(ar_menu);
+ }
+}
+
/**
* Check if a #uiAfterFunc is needed for this button.
*/
static bool ui_afterfunc_check(const uiBlock *block, const uiBut *but)
{
return (but->func || but->funcN || but->rename_func || but->optype || but->rnaprop || block->handle_func ||
- (but->type == UI_BTYPE_BUT_MENU && block->butm_func));
+ (but->type == UI_BTYPE_BUT_MENU && block->butm_func) ||
+ (block->handle && block->handle->popup_op));
}
static void ui_apply_but_func(bContext *C, uiBut *but)
@@ -681,6 +695,9 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
after->butm_func_arg = block->butm_func_arg;
after->a2 = but->a2;
}
+
+ if (block->handle)
+ after->popup_op = block->handle->popup_op;
after->optype = but->optype;
after->opcontext = but->opcontext;
@@ -765,6 +782,9 @@ static void ui_apply_but_funcs_after(bContext *C)
if (after.context)
CTX_store_set(C, after.context);
+ if (after.popup_op)
+ popup_check(C, after.popup_op);
+
if (after.opptr) {
/* free in advance to avoid leak on exit */
opptr = *after.opptr;
@@ -1420,87 +1440,82 @@ static bool ui_selectcontext_begin(
const bool is_array = RNA_property_array_check(prop);
const int rna_type = RNA_property_type(prop);
- if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) {
- goto finally;
- }
-
- selctx_data->elems_len = BLI_listbase_count(&lb);
- if (selctx_data->elems_len == 0) {
- goto finally;
- }
-
- selctx_data->elems = MEM_mallocN(sizeof(uiSelectContextElem) * selctx_data->elems_len, __func__);
+ if (UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path) &&
+ !BLI_listbase_is_empty(&lb))
+ {
+ selctx_data->elems_len = BLI_listbase_count(&lb);
+ selctx_data->elems = MEM_mallocN(sizeof(uiSelectContextElem) * selctx_data->elems_len, __func__);
- for (i = 0, link = lb.first; i < selctx_data->elems_len; i++, link = link->next) {
- uiSelectContextElem *other = &selctx_data->elems[i];
- /* TODO,. de-duplicate copy_to_selected_button */
- if (link->ptr.data != ptr.data) {
- if (use_path_from_id) {
- /* Path relative to ID. */
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.id.data, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else if (path) {
- /* Path relative to elements from list. */
- lprop = NULL;
- RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
- }
- else {
- lptr = link->ptr;
- lprop = prop;
- }
+ for (i = 0, link = lb.first; i < selctx_data->elems_len; i++, link = link->next) {
+ uiSelectContextElem *other = &selctx_data->elems[i];
+ /* TODO,. de-duplicate copy_to_selected_button */
+ if (link->ptr.data != ptr.data) {
+ if (use_path_from_id) {
+ /* Path relative to ID. */
+ lprop = NULL;
+ RNA_id_pointer_create(link->ptr.id.data, &idptr);
+ RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
+ }
+ else if (path) {
+ /* Path relative to elements from list. */
+ lprop = NULL;
+ RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
+ }
+ else {
+ lptr = link->ptr;
+ lprop = prop;
+ }
- /* lptr might not be the same as link->ptr! */
- if ((lptr.data != ptr.data) &&
- (lprop == prop) &&
- RNA_property_editable(&lptr, lprop))
- {
- other->ptr = lptr;
- if (is_array) {
- if (rna_type == PROP_FLOAT) {
- other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
- }
- else if (rna_type == PROP_INT) {
- other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
- }
- /* ignored for now */
+ /* lptr might not be the same as link->ptr! */
+ if ((lptr.data != ptr.data) &&
+ (lprop == prop) &&
+ RNA_property_editable(&lptr, lprop))
+ {
+ other->ptr = lptr;
+ if (is_array) {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
+ }
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
+ }
+ /* ignored for now */
#if 0
- else if (rna_type == PROP_BOOLEAN) {
- other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
- }
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
+ }
#endif
- }
- else {
- if (rna_type == PROP_FLOAT) {
- other->val_f = RNA_property_float_get(&lptr, lprop);
- }
- else if (rna_type == PROP_INT) {
- other->val_i = RNA_property_int_get(&lptr, lprop);
}
- /* ignored for now */
+ else {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get(&lptr, lprop);
+ }
+ /* ignored for now */
#if 0
- else if (rna_type == PROP_BOOLEAN) {
- other->val_b = RNA_property_boolean_get(&lptr, lprop);
- }
- else if (rna_type == PROP_ENUM) {
- other->val_i = RNA_property_enum_get(&lptr, lprop);
- }
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_ENUM) {
+ other->val_i = RNA_property_enum_get(&lptr, lprop);
+ }
#endif
- }
+ }
- continue;
+ continue;
+ }
}
+
+ selctx_data->elems_len -= 1;
+ i -= 1;
}
- selctx_data->elems_len -= 1;
- i -= 1;
+ success = (selctx_data->elems_len != 0);
}
}
- success = (selctx_data->elems_len != 0);
-
-finally:
if (selctx_data->elems_len == 0) {
MEM_SAFE_FREE(selctx_data->elems);
}
@@ -2299,7 +2314,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
/* Get many decimal places, then strip trailing zeros.
* note: too high values start to give strange results */
char buf_copy[UI_MAX_DRAW_STR];
- ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), UI_PRECISION_FLOAT_MAX);
+ ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), UI_PRECISION_FLOAT_MAX, false, NULL);
BLI_str_rstrip_float_zero(buf_copy, '\0');
WM_clipboard_text_set(buf_copy, 0);
@@ -2563,6 +2578,18 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *bu
}
}
+static void ui_but_text_clear(bContext *C, uiBut *but, uiHandleButtonData *data)
+{
+ /* most likely NULL, but let's check, and give it temp zero string */
+ if (!data->str) {
+ data->str = MEM_callocN(1, "temp str");
+ }
+ data->str[0] = 0;
+
+ ui_apply_but_TEX(C, but, data);
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+}
+
/* ************* in-button text selection/editing ************* */
@@ -2950,7 +2977,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
if (pbuf) {
if (ui_but_is_utf8(but)) {
- buf_len -= BLI_utf8_invalid_strip(pbuf, buf_len);
+ buf_len -= BLI_utf8_invalid_strip(pbuf, (size_t)buf_len);
}
ui_textedit_insert_buf(but, data, pbuf, buf_len);
@@ -3028,6 +3055,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
wmWindow *win = CTX_wm_window(C);
int len;
const bool is_num_but = ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER);
+ bool no_zero_strip = false;
if (data->str) {
MEM_freeN(data->str);
@@ -3060,14 +3088,16 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
data->maxlen = ui_but_string_get_max_length(but);
if (data->maxlen != 0) {
data->str = MEM_callocN(sizeof(char) * data->maxlen, "textedit str");
- ui_but_string_get(but, data->str, data->maxlen);
+ /* We do not want to truncate precision to default here, it's nice to show value,
+ * not to edit it - way too much precision is lost then. */
+ ui_but_string_get_ex(but, data->str, data->maxlen, UI_PRECISION_FLOAT_MAX, true, &no_zero_strip);
}
else {
data->is_str_dynamic = true;
data->str = ui_but_string_get_dynamic(but, &data->maxlen);
}
- if (ui_but_is_float(but) && !ui_but_is_unit(but) && !ui_but_anim_expression_get(but, NULL, 0)) {
+ if (ui_but_is_float(but) && !ui_but_is_unit(but) && !ui_but_anim_expression_get(but, NULL, 0) && !no_zero_strip) {
BLI_str_rstrip_float_zero(data->str, '\0');
}
@@ -3346,7 +3376,7 @@ static void ui_do_but_textedit(
if (event->type == WHEELDOWNMOUSE) {
break;
}
- /* fall-through */
+ ATTR_FALLTHROUGH;
case ENDKEY:
ui_textedit_move(but, data, STRCUR_DIR_NEXT,
event->shift != 0, STRCUR_JUMP_ALL);
@@ -3364,7 +3394,7 @@ static void ui_do_but_textedit(
if (event->type == WHEELUPMOUSE) {
break;
}
- /* fall-through */
+ ATTR_FALLTHROUGH;
case HOMEKEY:
ui_textedit_move(but, data, STRCUR_DIR_PREV,
event->shift != 0, STRCUR_JUMP_ALL);
@@ -3842,6 +3872,21 @@ static int ui_do_but_KEYEVT(
return WM_UI_HANDLER_CONTINUE;
}
+static bool ui_but_is_mouse_over_icon_extra(const ARegion *region, uiBut *but, const int mouse_xy[2])
+{
+ int x = mouse_xy[0], y = mouse_xy[1];
+ rcti icon_rect;
+
+ BLI_assert(ui_but_icon_extra_get(but) != UI_BUT_ICONEXTRA_NONE);
+
+ ui_window_to_block(region, but->block, &x, &y);
+
+ BLI_rcti_rctf_copy(&icon_rect, &but->rect);
+ icon_rect.xmin = icon_rect.xmax - (BLI_rcti_size_y(&icon_rect));
+
+ return BLI_rcti_isect_pt(&icon_rect, x, y);
+}
+
static int ui_do_but_TEX(
bContext *C, uiBlock *block, uiBut *but,
uiHandleButtonData *data, const wmEvent *event)
@@ -3855,7 +3900,14 @@ static int ui_do_but_TEX(
/* pass */
}
else {
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ const bool has_icon_extra = ui_but_icon_extra_get(but) == UI_BUT_ICONEXTRA_CLEAR;
+
+ if (has_icon_extra && ui_but_is_mouse_over_icon_extra(data->region, but, &event->x)) {
+ ui_but_text_clear(C, but, data);
+ }
+ else {
+ button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ }
return WM_UI_HANDLER_BREAK;
}
}
@@ -3876,47 +3928,29 @@ static int ui_do_but_SEARCH_UNLINK(
bContext *C, uiBlock *block, uiBut *but,
uiHandleButtonData *data, const wmEvent *event)
{
- uiButExtraIconType extra_icon_type;
+ const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but);
+ const bool has_icon_extra = (extra_icon_type != UI_BUT_ICONEXTRA_NONE);
/* unlink icon is on right */
if ((ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) &&
- ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
+ (has_icon_extra == true) &&
+ (ui_but_is_mouse_over_icon_extra(data->region, but, &event->x) == true))
{
- ARegion *ar = data->region;
- rcti rect;
- int x = event->x, y = event->y;
-
- ui_window_to_block(ar, but->block, &x, &y);
-
- BLI_rcti_rctf_copy(&rect, &but->rect);
-
- rect.xmin = rect.xmax - (BLI_rcti_size_y(&rect));
- /* handle click on unlink/eyedropper icon */
- if (BLI_rcti_isect_pt(&rect, x, y)) {
- /* doing this on KM_PRESS calls eyedropper after clicking unlink icon */
- if (event->val == KM_RELEASE) {
- /* unlink */
- if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) {
- /* most likely NULL, but let's check, and give it temp zero string */
- if (data->str == NULL) {
- data->str = MEM_callocN(1, "temp str");
- }
- data->str[0] = 0;
-
- ui_apply_but_TEX(C, but, data);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- /* eyedropper */
- else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
- WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
- }
- else {
- BLI_assert(0);
- }
+ /* doing this on KM_PRESS calls eyedropper after clicking unlink icon */
+ if (event->val == KM_RELEASE) {
+ /* unlink */
+ if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
+ ui_but_text_clear(C, but, data);
+ }
+ /* eyedropper */
+ else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
+ WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
+ }
+ else {
+ BLI_assert(0);
}
-
- return WM_UI_HANDLER_BREAK;
}
+ return WM_UI_HANDLER_BREAK;
}
return ui_do_but_TEX(C, block, but, data, event);
}
@@ -4261,7 +4295,7 @@ static bool ui_numedit_but_NUM(
if (!is_float) {
- temp = iroundf(tempf);
+ temp = round_fl_to_int(tempf);
temp = ui_numedit_apply_snap(temp, softmin, softmax, snap);
@@ -4546,7 +4580,7 @@ static bool ui_numedit_but_SLI(
tempf = softmin + f * softrange;
- temp = iroundf(tempf);
+ temp = round_fl_to_int(tempf);
if (snap) {
if (tempf == softmin || tempf == softmax) {
@@ -6648,7 +6682,7 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but);
+ UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but, NULL);
}
/**
@@ -6687,10 +6721,41 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa)
UI_popup_menu_end(C, pup);
}
+static void ui_but_menu_add_path_operators(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop)
+{
+ const PropertySubType subtype = RNA_property_subtype(prop);
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
+ char filepath[FILE_MAX];
+ char dir[FILE_MAXDIR];
+ char file[FILE_MAXFILE];
+ PointerRNA props_ptr;
+
+ BLI_assert(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH));
+ UNUSED_VARS_NDEBUG(subtype);
+
+ RNA_property_string_get(ptr, prop, filepath);
+ BLI_split_dirfile(filepath, dir, file, sizeof(dir), sizeof(file));
+
+ if (file[0]) {
+ BLI_assert(subtype == PROP_FILEPATH);
+
+ props_ptr = uiItemFullO_ptr(
+ layout, ot, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open File Externally"),
+ ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_string_set(&props_ptr, "filepath", filepath);
+ }
+
+ props_ptr = uiItemFullO_ptr(
+ layout, ot, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Location Externally"),
+ ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_string_set(&props_ptr, "filepath", dir);
+}
+
static bool ui_but_menu(bContext *C, uiBut *but)
{
uiPopupMenu *pup;
uiLayout *layout;
+ MenuType *mt = WM_menutype_find("WM_MT_button_context", true);
bool is_array, is_array_component;
uiStringInfo label = {BUT_GET_LABEL, NULL};
@@ -6715,11 +6780,19 @@ static bool ui_but_menu(bContext *C, uiBut *but)
if (but->rnapoin.data && but->rnaprop) {
PointerRNA *ptr = &but->rnapoin;
PropertyRNA *prop = but->rnaprop;
+ const PropertyType type = RNA_property_type(prop);
+ const PropertySubType subtype = RNA_property_subtype(prop);
bool is_anim = RNA_property_animateable(ptr, prop);
bool is_editable = RNA_property_editable(ptr, prop);
/*bool is_idprop = RNA_property_is_idprop(prop);*/ /* XXX does not work as expected, not strictly needed */
bool is_set = RNA_property_is_set(ptr, prop);
+ /* set the prop and pointer data for python access to the hovered ui element; TODO, index could be supported as well*/
+ PointerRNA temp_ptr;
+ RNA_pointer_create(NULL, &RNA_Property, but->rnaprop, &temp_ptr);
+ uiLayoutSetContextPointer(layout, "button_prop", &temp_ptr);
+ uiLayoutSetContextPointer(layout, "button_pointer", ptr);
+
/* second slower test, saved people finding keyframe items in menus when its not possible */
if (is_anim)
is_anim = RNA_property_path_from_ID_check(&but->rnapoin, but->rnaprop);
@@ -6885,6 +6958,11 @@ static bool ui_but_menu(bContext *C, uiBut *but)
ICON_NONE, "UI_OT_copy_data_path_button");
uiItemS(layout);
+
+ if (type == PROP_STRING && ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)) {
+ ui_but_menu_add_path_operators(layout, ptr, prop);
+ uiItemS(layout);
+ }
}
/* Operator buttons */
@@ -6930,7 +7008,12 @@ static bool ui_but_menu(bContext *C, uiBut *but)
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
UI_but_func_set(but2, popup_add_shortcut_func, but, NULL);
}
-
+
+ /* Set the operator pointer for python access */
+ if (but->opptr) {
+ uiLayoutSetContextPointer(layout, "button_operator", but->opptr);
+ }
+
uiItemS(layout);
}
@@ -6951,20 +7034,17 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
ICON_URL, "WM_OT_doc_view_manual_ui_context");
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
+ ptr_props = uiItemFullO(layout, "WM_OT_doc_view",
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
+ ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view",
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
/* XXX inactive option, not for public! */
#if 0
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_edit");
+ ptr_props = uiItemFullO(layout, "WM_OT_doc_edit",
+ "Submit Description", ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr_props, "doc_id", buf);
RNA_string_set(&ptr_props, "doc_new", RNA_property_description(but->rnaprop));
-
- uiItemFullO(layout, "WM_OT_doc_edit",
- "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
#endif
}
}
@@ -6980,6 +7060,14 @@ static bool ui_but_menu(bContext *C, uiBut *but)
}
uiItemFullO(layout, "UI_OT_edittranslation_init", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0);
+ mt = WM_menutype_find("WM_MT_button_context", true);
+ if (mt) {
+ Menu menu = {NULL};
+ menu.layout = uiLayoutColumn(layout, false);
+ menu.type = mt;
+ mt->draw(C, &menu);
+ }
+
UI_popup_menu_end(C, pup);
return true;
@@ -7091,7 +7179,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_TEXT:
case UI_BTYPE_SEARCH_MENU:
if ((but->type == UI_BTYPE_SEARCH_MENU) &&
- (but->flag & UI_BUT_SEARCH_UNLINK))
+ (but->flag & UI_BUT_VALUE_CLEAR))
{
retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event);
if (retval & WM_UI_HANDLER_BREAK) {
@@ -7687,7 +7775,8 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
if (ui_but_is_cursor_warp(but)) {
#ifdef USE_CONT_MOUSE_CORRECT
- if (data->ungrab_mval[0] != FLT_MAX) {
+ /* stereo3d has issues with changing cursor location so rather avoid */
+ if (data->ungrab_mval[0] != FLT_MAX && !WM_stereo3d_enabled(data->window, false)) {
int mouse_ungrab_xy[2];
ui_block_to_window_fl(data->region, but->block, &data->ungrab_mval[0], &data->ungrab_mval[1]);
mouse_ungrab_xy[0] = data->ungrab_mval[0];
@@ -8318,7 +8407,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
case MIDDLEMOUSE:
case MOUSEPAN:
UI_but_tooltip_timer_remove(C, but);
- /* fall-through */
+ ATTR_FALLTHROUGH;
default:
/* handle button type specific events */
retval = ui_do_button(C, block, but, event);
@@ -9112,23 +9201,23 @@ static int ui_handle_menu_event(
break;
case ONEKEY: case PAD1:
- act = 1;
+ act = 1; ATTR_FALLTHROUGH;
case TWOKEY: case PAD2:
- if (act == 0) act = 2;
+ if (act == 0) act = 2; ATTR_FALLTHROUGH;
case THREEKEY: case PAD3:
- if (act == 0) act = 3;
+ if (act == 0) act = 3; ATTR_FALLTHROUGH;
case FOURKEY: case PAD4:
- if (act == 0) act = 4;
+ if (act == 0) act = 4; ATTR_FALLTHROUGH;
case FIVEKEY: case PAD5:
- if (act == 0) act = 5;
+ if (act == 0) act = 5; ATTR_FALLTHROUGH;
case SIXKEY: case PAD6:
- if (act == 0) act = 6;
+ if (act == 0) act = 6; ATTR_FALLTHROUGH;
case SEVENKEY: case PAD7:
- if (act == 0) act = 7;
+ if (act == 0) act = 7; ATTR_FALLTHROUGH;
case EIGHTKEY: case PAD8:
- if (act == 0) act = 8;
+ if (act == 0) act = 8; ATTR_FALLTHROUGH;
case NINEKEY: case PAD9:
- if (act == 0) act = 9;
+ if (act == 0) act = 9; ATTR_FALLTHROUGH;
case ZEROKEY: case PAD0:
if (act == 0) act = 10;
@@ -9155,11 +9244,17 @@ static int ui_handle_menu_event(
doit = true;
}
}
- else if (count == act) {
+ else if (ELEM(but->type,
+ UI_BTYPE_BUT,
+ UI_BTYPE_BUT_MENU,
+ UI_BTYPE_MENU, UI_BTYPE_BLOCK,
+ UI_BTYPE_PULLDOWN) &&
+ count == act)
+ {
doit = true;
}
- if (doit) {
+ if (!(but->flag & UI_BUT_DISABLED) && doit) {
/* activate buttons but open menu's */
uiButtonActivateType activate;
if (but->type == UI_BTYPE_PULLDOWN) {
@@ -9213,8 +9308,7 @@ static int ui_handle_menu_event(
break;
for (but = block->buttons.first; but; but = but->next) {
-
- if (but->menu_key == event->type) {
+ if (!(but->flag & UI_BUT_DISABLED) && but->menu_key == event->type) {
if (ELEM(but->type, UI_BTYPE_BUT, UI_BTYPE_BUT_MENU)) {
/* mainly for operator buttons */
ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_APPLY);
@@ -9723,13 +9817,13 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
case (ZEROKEY + n): case (PAD0 + n): \
{ if (num_dir == UI_RADIAL_NONE) num_dir = d; } (void)0
- CASE_NUM_TO_DIR(1, UI_RADIAL_SW);
- CASE_NUM_TO_DIR(2, UI_RADIAL_S);
- CASE_NUM_TO_DIR(3, UI_RADIAL_SE);
- CASE_NUM_TO_DIR(4, UI_RADIAL_W);
- CASE_NUM_TO_DIR(6, UI_RADIAL_E);
- CASE_NUM_TO_DIR(7, UI_RADIAL_NW);
- CASE_NUM_TO_DIR(8, UI_RADIAL_N);
+ CASE_NUM_TO_DIR(1, UI_RADIAL_SW); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(2, UI_RADIAL_S); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(3, UI_RADIAL_SE); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(4, UI_RADIAL_W); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(6, UI_RADIAL_E); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(7, UI_RADIAL_NW); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(8, UI_RADIAL_N); ATTR_FALLTHROUGH;
CASE_NUM_TO_DIR(9, UI_RADIAL_NE);
{
but = ui_block_pie_dir_activate(block, event, num_dir);
@@ -10127,6 +10221,25 @@ void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle *
void UI_popup_handlers_remove(ListBase *handlers, uiPopupBlockHandle *popup)
{
+ wmEventHandler *handler;
+
+ for (handler = handlers->first; handler; handler = handler->next) {
+ if (handler->ui_handle == ui_popup_handler &&
+ handler->ui_remove == ui_popup_handler_remove &&
+ handler->ui_userdata == popup)
+ {
+ /* tag refresh parent popup */
+ if (handler->next &&
+ handler->next->ui_handle == ui_popup_handler &&
+ handler->next->ui_remove == ui_popup_handler_remove)
+ {
+ uiPopupBlockHandle *parent_popup = handler->next->ui_userdata;
+ ED_region_tag_refresh_ui(parent_popup->region);
+ }
+ break;
+ }
+ }
+
WM_event_remove_ui_handler(handlers, ui_popup_handler, ui_popup_handler_remove, popup, false);
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index fcf827bdbe6..ab760c40451 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -127,7 +127,7 @@ enum {
* (e.g. 'x' icon in search menu) - used with ui_but_icon_extra_get */
typedef enum uiButExtraIconType {
UI_BUT_ICONEXTRA_NONE = 1,
- UI_BUT_ICONEXTRA_UNLINK,
+ UI_BUT_ICONEXTRA_CLEAR,
UI_BUT_ICONEXTRA_EYEDROPPER,
} uiButExtraIconType;
@@ -473,7 +473,9 @@ extern void ui_hsvcircle_pos_from_vals(struct uiBut *but, const rcti *rect, floa
extern void ui_hsvcube_pos_from_vals(struct uiBut *but, const rcti *rect, float *hsv, float *xp, float *yp);
bool ui_but_is_colorpicker_display_space(struct uiBut *but);
-extern void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision) ATTR_NONNULL();
+extern void ui_but_string_get_ex(
+ uiBut *but, char *str, const size_t maxlen,
+ const int float_precision, const bool use_exp_float, bool *r_use_exp_float) ATTR_NONNULL(1, 2);
extern void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ATTR_NONNULL();
extern char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size);
extern void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL();
@@ -556,6 +558,7 @@ struct uiPopupBlockHandle {
struct uiKeyNavLock keynav_state;
/* for operator popups */
+ struct wmOperator *popup_op;
struct wmOperatorType *optype;
ScrArea *ctx_area;
ARegion *ctx_region;
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 875522e01c6..c21a76918e8 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -125,6 +125,13 @@ typedef struct uiItem {
int flag;
} uiItem;
+enum {
+ UI_ITEM_FIXED = 1 << 0,
+ UI_ITEM_MIN = 1 << 1,
+
+ UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
+};
+
typedef struct uiButtonItem {
uiItem item;
uiBut *but;
@@ -184,29 +191,37 @@ static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_
return name;
}
-static int ui_item_fit(int item, int pos, int all, int available, bool is_last, int alignment)
+static int ui_item_fit(int item, int pos, int all, int available, bool is_last, int alignment, float *extra_pixel)
{
/* available == 0 is unlimited */
- if (available == 0)
+ if (ELEM(0, available, all)) {
return item;
+ }
if (all > available) {
/* contents is bigger than available space */
if (is_last)
return available - pos;
- else
- return (item * available) / all;
+ else {
+ float width = *extra_pixel + (item * available) / (float)all;
+ *extra_pixel = width - (int)width;
+ return (int)width;
+ }
}
else {
/* contents is smaller or equal to available space */
if (alignment == UI_LAYOUT_ALIGN_EXPAND) {
if (is_last)
return available - pos;
- else
- return (item * available) / all;
+ else {
+ float width = *extra_pixel + (item * available) / (float)all;
+ *extra_pixel = width - (int)width;
+ return (int)width;
+ }
}
- else
+ else {
return item;
+ }
}
}
@@ -232,6 +247,9 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool
variable = (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X);
if (variable) {
+ if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
+ layout->item.flag |= UI_ITEM_MIN;
+ }
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
/* it may seem odd that the icon only adds (UI_UNIT_X / 4)
* but taking margins into account its fine */
@@ -296,6 +314,26 @@ static void ui_item_position(uiItem *item, int x, int y, int w, int h)
}
}
+static void ui_item_move(uiItem *item, int delta_xmin, int delta_xmax)
+{
+ if (item->type == ITEM_BUTTON) {
+ uiButtonItem *bitem = (uiButtonItem *)item;
+
+ bitem->but->rect.xmin += delta_xmin;
+ bitem->but->rect.xmax += delta_xmax;
+
+ ui_but_update(bitem->but); /* for strlen */
+ }
+ else {
+ uiLayout *litem = (uiLayout *)item;
+
+ if (delta_xmin > 0)
+ litem->x += delta_xmin;
+ else
+ litem->w += delta_xmax;
+ }
+}
+
/******************** Special RNA Items *********************/
static int ui_layout_local_dir(uiLayout *layout)
@@ -570,8 +608,16 @@ static void ui_item_enum_expand(
/* we dont want nested rows, cols in menus */
if (radial) {
- layout_radial = uiLayoutRadial(layout);
- UI_block_layout_set_current(block, layout_radial);
+ if (layout->root->layout == layout) {
+ layout_radial = uiLayoutRadial(layout);
+ UI_block_layout_set_current(block, layout_radial);
+ }
+ else {
+ if (layout->item.type == ITEM_LAYOUT_RADIAL) {
+ layout_radial = layout;
+ }
+ UI_block_layout_set_current(block, layout);
+ }
}
else if (layout->root->type != UI_LAYOUT_MENU) {
UI_block_layout_set_current(block, ui_item_local_sublayout(layout, layout, 1));
@@ -582,8 +628,9 @@ static void ui_item_enum_expand(
for (item = item_array; item->identifier; item++) {
if (!item->identifier[0]) {
- if (radial)
+ if (radial && layout_radial) {
uiItemS(layout_radial);
+ }
continue;
}
@@ -659,7 +706,7 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n
WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, NULL);
}
else if (flag & UI_ITEM_R_EVENT) {
- uiDefButR_prop(block, UI_BTYPE_KEY_EVENT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefButR_prop(block, UI_BTYPE_KEY_EVENT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL);
}
else if (flag & UI_ITEM_R_FULL_EVENT) {
if (RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) {
@@ -1230,8 +1277,16 @@ static void ui_item_rna_size(
}
}
- if (!w)
- w = ui_text_icon_width(layout, name, icon, 0);
+ if (!w) {
+ if (type == PROP_ENUM && icon_only) {
+ w = ui_text_icon_width(layout, "", ICON_BLANK1, 0);
+ if (index != RNA_ENUM_VALUE)
+ w += 0.6f * UI_UNIT_X;
+ }
+ else {
+ w = ui_text_icon_width(layout, name, icon, 0);
+ }
+ }
h = UI_UNIT_Y;
/* increase height for arrays */
@@ -1249,7 +1304,7 @@ static void ui_item_rna_size(
else if (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
if (type == PROP_BOOLEAN && name[0])
w += UI_UNIT_X / 5;
- else if (type == PROP_ENUM)
+ else if (type == PROP_ENUM && !icon_only)
w += UI_UNIT_X / 4;
else if (type == PROP_FLOAT || type == PROP_INT)
w += UI_UNIT_X * 3;
@@ -1451,8 +1506,9 @@ void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *pr
for (a = 0; item[a].identifier; a++) {
if (item[a].value == ivalue) {
const char *item_name = name ? name : CTX_IFACE_(RNA_property_translation_context(prop), item[a].name);
+ const int flag = item_name[0] ? 0 : UI_ITEM_R_ICON_ONLY;
- uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name, icon ? icon : item[a].icon);
+ uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, flag, item_name, icon ? icon : item[a].icon);
break;
}
}
@@ -1659,7 +1715,7 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
but->rnasearchprop = searchprop;
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
if (RNA_property_is_unlink(prop)) {
- but->flag |= UI_BUT_SEARCH_UNLINK;
+ but->flag |= UI_BUT_VALUE_CLEAR;
}
if (RNA_property_type(prop) == PROP_ENUM) {
@@ -1670,6 +1726,10 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
UI_but_func_search_set(but, ui_searchbox_create_generic, rna_search_cb, but, NULL, NULL);
}
+ else if (but->type == UI_BTYPE_SEARCH_MENU) {
+ /* In case we fail to find proper searchprop, so other code might have already set but->type to search menu... */
+ but->type = UI_BTYPE_LABEL;
+ }
}
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
@@ -2047,6 +2107,7 @@ static void ui_litem_estimate_row(uiLayout *litem)
{
uiItem *item;
int itemw, itemh;
+ bool min_size_flag = true;
litem->w = 0;
litem->h = 0;
@@ -2054,12 +2115,18 @@ static void ui_litem_estimate_row(uiLayout *litem)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+
litem->w += itemw;
litem->h = MAX2(itemh, litem->h);
if (item->next)
litem->w += litem->space;
}
+
+ if (min_size_flag) {
+ litem->item.flag |= UI_ITEM_MIN;
+ }
}
static int ui_litem_min_width(int itemw)
@@ -2069,9 +2136,10 @@ static int ui_litem_min_width(int itemw)
static void ui_litem_layout_row(uiLayout *litem)
{
- uiItem *item;
+ uiItem *item, *last_free_item = NULL;
int x, y, w, tot, totw, neww, newtotw, itemw, minw, itemh, offset;
int fixedw, freew, fixedx, freex, flag = 0, lastw = 0;
+ float extra_pixel;
/* x = litem->x; */ /* UNUSED */
y = litem->y;
@@ -2098,31 +2166,45 @@ static void ui_litem_layout_row(uiLayout *litem)
x = 0;
flag = 0;
newtotw = totw;
+ extra_pixel = 0.0f;
for (item = litem->items.first; item; item = item->next) {
- if (item->flag)
+ if (item->flag & UI_ITEM_FIXED)
continue;
ui_item_size(item, &itemw, &itemh);
minw = ui_litem_min_width(itemw);
if (w - lastw > 0)
- neww = ui_item_fit(itemw, x, totw, w - lastw, !item->next, litem->alignment);
+ neww = ui_item_fit(itemw, x, totw, w - lastw, !item->next, litem->alignment, &extra_pixel);
else
neww = 0; /* no space left, all will need clamping to minimum size */
x += neww;
- if ((neww < minw || itemw == minw) && w != 0) {
+ bool min_flag = item->flag & UI_ITEM_MIN;
+ /* ignore min flag for rows with right or center alignment */
+ if (item->type != ITEM_BUTTON &&
+ ELEM(((uiLayout *)item)->alignment, UI_LAYOUT_ALIGN_RIGHT, UI_LAYOUT_ALIGN_CENTER) &&
+ litem->alignment == UI_LAYOUT_ALIGN_EXPAND &&
+ ((uiItem *)litem)->flag & UI_ITEM_MIN)
+ {
+ min_flag = false;
+ }
+
+ if ((neww < minw || min_flag) && w != 0) {
/* fixed size */
- item->flag = 1;
+ item->flag |= UI_ITEM_FIXED;
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ minw = itemw;
+ }
fixedw += minw;
flag = 1;
newtotw -= itemw;
}
else {
/* keep free size */
- item->flag = 0;
+ item->flag &= ~UI_ITEM_FIXED;
freew += itemw;
}
}
@@ -2133,21 +2215,26 @@ static void ui_litem_layout_row(uiLayout *litem)
freex = 0;
fixedx = 0;
+ extra_pixel = 0.0f;
x = litem->x;
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
minw = ui_litem_min_width(itemw);
- if (item->flag) {
+ if (item->flag & UI_ITEM_FIXED) {
/* fixed minimum size items */
- itemw = ui_item_fit(minw, fixedx, fixedw, min_ii(w, fixedw), !item->next, litem->alignment);
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ minw = itemw;
+ }
+ itemw = ui_item_fit(minw, fixedx, fixedw, min_ii(w, fixedw), !item->next, litem->alignment, &extra_pixel);
fixedx += itemw;
}
else {
/* free size item */
- itemw = ui_item_fit(itemw, freex, freew, w - fixedw, !item->next, litem->alignment);
+ itemw = ui_item_fit(itemw, freex, freew, w - fixedw, !item->next, litem->alignment, &extra_pixel);
freex += itemw;
+ last_free_item = item;
}
/* align right/center */
@@ -2169,6 +2256,17 @@ static void ui_litem_layout_row(uiLayout *litem)
x += litem->space;
}
+ /* add extra pixel */
+ uiItem *last_item = litem->items.last;
+ extra_pixel = litem->w - (x - litem->x);
+ if (extra_pixel > 0 && litem->alignment == UI_LAYOUT_ALIGN_EXPAND &&
+ last_free_item && last_item && last_item->flag & UI_ITEM_FIXED)
+ {
+ ui_item_move(last_free_item, 0, extra_pixel);
+ for (item = last_free_item->next; item; item = item->next)
+ ui_item_move(item, extra_pixel, extra_pixel);
+ }
+
litem->w = x - litem->x;
litem->h = litem->y - y;
litem->x = x;
@@ -2176,10 +2274,11 @@ static void ui_litem_layout_row(uiLayout *litem)
}
/* single-column layout */
-static void ui_litem_estimate_column(uiLayout *litem)
+static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
{
uiItem *item;
int itemw, itemh;
+ bool min_size_flag = true;
litem->w = 0;
litem->h = 0;
@@ -2187,15 +2286,21 @@ static void ui_litem_estimate_column(uiLayout *litem)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+
litem->w = MAX2(litem->w, itemw);
litem->h += itemh;
- if (item->next)
+ if (item->next && (!is_box || item != litem->items.first))
litem->h += litem->space;
}
+
+ if (min_size_flag) {
+ litem->item.flag |= UI_ITEM_MIN;
+ }
}
-static void ui_litem_layout_column(uiLayout *litem)
+static void ui_litem_layout_column(uiLayout *litem, bool is_box)
{
uiItem *item;
int itemh, x, y;
@@ -2209,8 +2314,12 @@ static void ui_litem_layout_column(uiLayout *litem)
y -= itemh;
ui_item_position(item, x, y, litem->w, itemh);
- if (item->next)
+ if (item->next && (!is_box || item != litem->items.first))
y -= litem->space;
+
+ if (is_box) {
+ item->flag |= UI_ITEM_BOX_ITEM;
+ }
}
litem->h = litem->y - y;
@@ -2301,8 +2410,10 @@ static void ui_litem_layout_radial(uiLayout *litem)
/* add a little bit more here to include number */
bitem->but->rect.xmax += 1.5f * UI_UNIT_X;
/* enable drawing as pie item if supported by widget */
- if (ui_item_is_radial_drawable(bitem))
+ if (ui_item_is_radial_drawable(bitem)) {
bitem->but->dt = UI_EMBOSS_RADIAL;
+ bitem->but->drawflag |= UI_BUT_ICON_LEFT;
+ }
}
ui_item_size(item, &itemw, &itemh);
@@ -2351,7 +2462,7 @@ static void ui_litem_layout_root(uiLayout *litem)
else if (litem->root->type == UI_LAYOUT_PIEMENU)
ui_litem_layout_root_radial(litem);
else
- ui_litem_layout_column(litem);
+ ui_litem_layout_column(litem, false);
}
/* box layout */
@@ -2359,9 +2470,9 @@ static void ui_litem_estimate_box(uiLayout *litem)
{
uiStyle *style = litem->root->style;
- ui_litem_estimate_column(litem);
+ ui_litem_estimate_column(litem, true);
litem->w += 2 * style->boxspace;
- litem->h += style->boxspace;
+ litem->h += 2 * style->boxspace;
}
static void ui_litem_layout_box(uiLayout *litem)
@@ -2375,17 +2486,18 @@ static void ui_litem_layout_box(uiLayout *litem)
h = litem->h;
litem->x += style->boxspace;
+ litem->y -= style->boxspace;
if (w != 0) litem->w -= 2 * style->boxspace;
if (h != 0) litem->h -= 2 * style->boxspace;
- ui_litem_layout_column(litem);
+ ui_litem_layout_column(litem, true);
litem->x -= style->boxspace;
litem->y -= style->boxspace;
if (w != 0) litem->w += 2 * style->boxspace;
- if (h != 0) litem->h += style->boxspace;
+ if (h != 0) litem->h += 2 * style->boxspace;
/* roundbox around the sublayout */
but = box->roundbox;
@@ -2605,13 +2717,14 @@ static void ui_litem_layout_absolute(uiLayout *litem)
static void ui_litem_estimate_split(uiLayout *litem)
{
ui_litem_estimate_row(litem);
+ litem->item.flag &= ~UI_ITEM_MIN;
}
static void ui_litem_layout_split(uiLayout *litem)
{
uiLayoutItemSplit *split = (uiLayoutItemSplit *)litem;
uiItem *item;
- float percentage;
+ float percentage, extra_pixel = 0.0f;
const int tot = BLI_listbase_count(&litem->items);
int itemh, x, y, w, colw = 0;
@@ -2634,7 +2747,9 @@ static void ui_litem_layout_split(uiLayout *litem)
x += colw;
if (item->next) {
- colw = (w - (int)(w * percentage)) / (tot - 1);
+ const float width = extra_pixel + (w - (int)(w * percentage)) / ((float)tot - 1);
+ extra_pixel = width - (int)width;
+ colw = (int)width;
colw = MAX2(colw, 0);
x += litem->space;
@@ -3027,15 +3142,18 @@ static void ui_item_estimate(uiItem *item)
for (subitem = litem->items.first; subitem; subitem = subitem->next)
ui_item_estimate(subitem);
- if (BLI_listbase_is_empty(&litem->items))
+ if (BLI_listbase_is_empty(&litem->items)) {
+ litem->w = 0;
+ litem->h = 0;
return;
+ }
if (litem->scale[0] != 0.0f || litem->scale[1] != 0.0f)
ui_item_scale(litem, litem->scale);
switch (litem->item.type) {
case ITEM_LAYOUT_COLUMN:
- ui_litem_estimate_column(litem);
+ ui_litem_estimate_column(litem, false);
break;
case ITEM_LAYOUT_COLUMN_FLOW:
ui_litem_estimate_column_flow(litem);
@@ -3090,9 +3208,9 @@ static void ui_item_align(uiLayout *litem, short nr)
}
else if (item->type == ITEM_LAYOUT_BOX) {
box = (uiLayoutItemBx *)item;
- box->roundbox->alignnr = nr;
- BLI_remlink(&litem->root->block->buttons, box->roundbox);
- BLI_addhead(&litem->root->block->buttons, box->roundbox);
+ if (!box->roundbox->alignnr) {
+ box->roundbox->alignnr = nr;
+ }
}
else if (((uiLayout *)item)->align) {
ui_item_align((uiLayout *)item, nr);
@@ -3134,7 +3252,7 @@ static void ui_item_layout(uiItem *item)
switch (litem->item.type) {
case ITEM_LAYOUT_COLUMN:
- ui_litem_layout_column(litem);
+ ui_litem_layout_column(litem, false);
break;
case ITEM_LAYOUT_COLUMN_FLOW:
ui_litem_layout_column_flow(litem);
@@ -3164,8 +3282,18 @@ static void ui_item_layout(uiItem *item)
break;
}
- for (subitem = litem->items.first; subitem; subitem = subitem->next)
+ for (subitem = litem->items.first; subitem; subitem = subitem->next) {
+ if (item->flag & UI_ITEM_BOX_ITEM) {
+ subitem->flag |= UI_ITEM_BOX_ITEM;
+ }
ui_item_layout(subitem);
+ }
+ }
+ else {
+ if (item->flag & UI_ITEM_BOX_ITEM) {
+ uiButtonItem *bitem = (uiButtonItem *)item;
+ bitem->but->drawflag |= UI_BUT_BOX_ITEM;
+ }
}
}
@@ -3277,6 +3405,15 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
bitem = MEM_callocN(sizeof(uiButtonItem), "uiButtonItem");
bitem->item.type = ITEM_BUTTON;
bitem->but = but;
+
+ int w, h;
+ ui_item_size((uiItem *)bitem, &w, &h);
+ /* XXX uiBut hasn't scaled yet
+ * we can flag the button as not expandable, depending on its size */
+ if (w <= 2 * UI_UNIT_X && (!but->str || but->str[0] == '\0')) {
+ bitem->item.flag |= UI_ITEM_MIN;
+ }
+
BLI_addtail(&layout->items, bitem);
if (layout->context) {
@@ -3470,14 +3607,13 @@ void uiLayoutOperatorButs(
row = uiLayoutRow(layout, true);
uiItemM(row, (bContext *)C, "WM_MT_operator_presets", NULL, ICON_NONE);
- WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false);
+ op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMIN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&op_ptr, "operator", op->type->idname);
- uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMIN, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
- WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
+ op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMOUT, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&op_ptr, "operator", op->type->idname);
RNA_boolean_set(&op_ptr, "remove_active", true);
- uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMOUT, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
}
if (op->type->ui) {
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 40ebc946e79..d0c110d1db5 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -360,6 +360,9 @@ bool UI_context_copy_to_selected_list(
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
*r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_fcurves");
+ }
else if (RNA_struct_is_a(ptr->type, &RNA_Node) ||
RNA_struct_is_a(ptr->type, &RNA_NodeSocket))
{
@@ -494,51 +497,51 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
char *path = NULL;
bool use_path_from_id;
CollectionPointerLink *link;
- ListBase lb;
-
- if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path))
- return success;
+ ListBase lb = {NULL};
- for (link = lb.first; link; link = link->next) {
- if (link->ptr.data != ptr.data) {
- if (use_path_from_id) {
- /* Path relative to ID. */
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.id.data, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else if (path) {
- /* Path relative to elements from list. */
- lprop = NULL;
- RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
- }
- else {
- lptr = link->ptr;
- lprop = prop;
- }
+ if (UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path) &&
+ !BLI_listbase_is_empty(&lb))
+ {
+ for (link = lb.first; link; link = link->next) {
+ if (link->ptr.data != ptr.data) {
+ if (use_path_from_id) {
+ /* Path relative to ID. */
+ lprop = NULL;
+ RNA_id_pointer_create(link->ptr.id.data, &idptr);
+ RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
+ }
+ else if (path) {
+ /* Path relative to elements from list. */
+ lprop = NULL;
+ RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
+ }
+ else {
+ lptr = link->ptr;
+ lprop = prop;
+ }
- if (lptr.data == ptr.data) {
- /* lptr might not be the same as link->ptr! */
- continue;
- }
+ if (lptr.data == ptr.data) {
+ /* lptr might not be the same as link->ptr! */
+ continue;
+ }
- if (lprop == prop) {
- if (RNA_property_editable(&lptr, lprop)) {
- if (poll) {
- success = true;
- break;
- }
- else {
- if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) {
- RNA_property_update(C, &lptr, prop);
+ if (lprop == prop) {
+ if (RNA_property_editable(&lptr, lprop)) {
+ if (poll) {
success = true;
+ break;
+ }
+ else {
+ if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) {
+ RNA_property_update(C, &lptr, prop);
+ success = true;
+ }
}
}
}
}
}
}
-
MEM_SAFE_FREE(path);
BLI_freelistN(&lb);
}
@@ -739,6 +742,7 @@ static int editsource_text_edit(
if (text == NULL) {
text = BKE_text_load(bmain, filepath, bmain->name);
+ id_us_ensure_real(&text->id);
}
if (text == NULL) {
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index c131bcb8e14..d9685d7281b 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -496,14 +496,14 @@ static void ui_draw_panel_dragwidget(const rctf *rect)
const int col_tint = 84;
const int px = (int)U.pixelsize;
- const int px_zoom = max_ii(iroundf(BLI_rctf_size_y(rect) / 22.0f), 1);
+ const int px_zoom = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 22.0f), 1);
- const int box_margin = max_ii(iroundf((float)(px_zoom * 2.0f)), px);
- const int box_size = max_ii(iroundf((BLI_rctf_size_y(rect) / 8.0f) - px), px);
+ const int box_margin = max_ii(round_fl_to_int((float)(px_zoom * 2.0f)), px);
+ const int box_size = max_ii(round_fl_to_int((BLI_rctf_size_y(rect) / 8.0f) - px), px);
const int x_min = rect->xmin;
const int y_min = rect->ymin;
- const int y_ofs = max_ii(iroundf(BLI_rctf_size_y(rect) / 3.0f), px);
+ const int y_ofs = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 3.0f), px);
const int x_ofs = y_ofs;
int i_x, i_y;
@@ -877,8 +877,8 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo
for (a = 0; a < tot; a++, ps++) {
if ((ps->pa->flag & PNL_SELECT) == 0) {
if ((ps->orig->ofsx != ps->pa->ofsx) || (ps->orig->ofsy != ps->pa->ofsy)) {
- ps->orig->ofsx = iroundf(fac * (float)ps->pa->ofsx + (1.0f - fac) * (float)ps->orig->ofsx);
- ps->orig->ofsy = iroundf(fac * (float)ps->pa->ofsy + (1.0f - fac) * (float)ps->orig->ofsy);
+ ps->orig->ofsx = round_fl_to_int(fac * (float)ps->pa->ofsx + (1.0f - fac) * (float)ps->orig->ofsx);
+ ps->orig->ofsy = round_fl_to_int(fac * (float)ps->pa->ofsy + (1.0f - fac) * (float)ps->orig->ofsy);
done = true;
}
}
@@ -1281,7 +1281,7 @@ static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, voi
static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was_open)
{
wmWindow *win = CTX_wm_window(C);
- wmEvent *event = win->eventstate;
+ const wmEvent *event = win->eventstate;
uiPanelDragCollapseHandle *dragcol_data = MEM_mallocN(sizeof(*dragcol_data), __func__);
dragcol_data->was_first_open = was_open;
@@ -1615,11 +1615,11 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
PanelCategoryDyn *pc_dyn;
const float aspect = ((uiBlock *)ar->uiblocks.first)->aspect;
const float zoom = 1.0f / aspect;
- const int px = max_ii(1, iroundf(U.pixelsize));
- const int category_tabs_width = iroundf(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom);
+ const int px = max_ii(1, round_fl_to_int(U.pixelsize));
+ const int category_tabs_width = round_fl_to_int(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom);
const float dpi_fac = UI_DPI_FAC;
- const int tab_v_pad_text = iroundf((2 + ((px * 3) * dpi_fac)) * zoom); /* pading of tabs around text */
- const int tab_v_pad = iroundf((4 + (2 * px * dpi_fac)) * zoom); /* padding between tabs */
+ const int tab_v_pad_text = round_fl_to_int((2 + ((px * 3) * dpi_fac)) * zoom); /* pading of tabs around text */
+ const int tab_v_pad = round_fl_to_int((4 + (2 * px * dpi_fac)) * zoom); /* padding between tabs */
const float tab_curve_radius = ((px * 3) * dpi_fac) * zoom;
const int roundboxtype = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT;
bool is_alpha;
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index cdf34642a8d..71124cf8eb7 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -342,11 +342,13 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
/* Tip */
if (but_tip.strinfo) {
- BLI_strncpy(data->header, but_tip.strinfo, sizeof(data->lines[0]));
if (enum_label.strinfo) {
BLI_snprintf(data->header, sizeof(data->header), "%s: ", but_tip.strinfo);
BLI_strncpy(data->active_info, enum_label.strinfo, sizeof(data->lines[0]));
}
+ else {
+ BLI_snprintf(data->header, sizeof(data->header), "%s.", but_tip.strinfo);
+ }
data->format[data->totline].style = UI_TIP_STYLE_HEADER;
data->totline++;
@@ -851,7 +853,7 @@ static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step)
}
else {
/* only let users step into an 'unset' state for unlink buttons */
- data->active = (but->flag & UI_BUT_SEARCH_UNLINK) ? -1 : 0;
+ data->active = (but->flag & UI_BUT_VALUE_CLEAR) ? -1 : 0;
}
}
@@ -922,8 +924,8 @@ bool ui_searchbox_apply(uiBut *but, ARegion *ar)
return true;
}
- else if (but->flag & UI_BUT_SEARCH_UNLINK) {
- /* It is valid for _UNLINK flavor to have no active element (it's a valid way to unlink). */
+ else if (but->flag & UI_BUT_VALUE_CLEAR) {
+ /* It is valid for _VALUE_CLEAR flavor to have no active element (it's a valid way to unlink). */
but->editstr[0] = '\0';
return true;
@@ -1692,6 +1694,28 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar)
UI_block_draw(C, block);
}
+/**
+ * Use to refresh centered popups on screen resizing (for splash).
+ */
+static void ui_block_region_popup_window_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+{
+ switch (wmn->category) {
+ case NC_WINDOW:
+ {
+ switch (wmn->action) {
+ case NA_EDITED:
+ {
+ /* window resize */
+ ED_region_tag_refresh_ui(ar);
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
static void ui_popup_block_clip(wmWindow *window, uiBlock *block)
{
uiBut *bt;
@@ -1845,8 +1869,9 @@ uiBlock *ui_popup_block_refresh(
/* defer this until blocks are translated (below) */
block->oldblock = NULL;
- if (!block->endblock)
- UI_block_end_ex(C, block, handle->popup_create_vars.event_xy);
+ if (!block->endblock) {
+ UI_block_end_ex(C, block, handle->popup_create_vars.event_xy, handle->popup_create_vars.event_xy);
+ }
/* if this is being created from a button */
if (but) {
@@ -2003,6 +2028,11 @@ uiPopupBlockHandle *ui_popup_block_create(
block = ui_popup_block_refresh(C, handle, butregion, but);
handle = block->handle;
+ /* keep centered on window resizing */
+ if ((block->bounds_type == UI_BLOCK_BOUNDS_POPUP_CENTER) && handle->can_refresh) {
+ type.listener = ui_block_region_popup_window_listener;
+ }
+
return handle;
}
@@ -2072,9 +2102,11 @@ static void ui_update_color_picker_buts_rgb(uiBlock *block, ColorPicker *cpicker
continue;
if (bt->rnaprop) {
-
ui_but_v3_set(bt, rgb);
+ /* original button that created the color picker already does undo
+ * push, so disable it on RNA buttons in the color picker block */
+ UI_but_flag_disable(bt, UI_BUT_UNDO);
}
else if (STREQ(bt->str, "Hex: ")) {
float rgb_gamma[3];
@@ -2411,7 +2443,7 @@ static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr,
BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, ));
yco = -3.0f * UI_UNIT_Y;
- bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 7, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
+ bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol);
bt->custom_data = cpicker;
uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y, butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
@@ -2923,8 +2955,8 @@ uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, co
pie->block_radial->puphash = ui_popup_menu_hash(title);
pie->block_radial->flag |= UI_BLOCK_RADIAL;
- /* if pie is spawned by a left click, it is always assumed to be click style */
- if (event->type == LEFTMOUSE) {
+ /* if pie is spawned by a left click, release or click event, it is always assumed to be click style */
+ if (event->type == LEFTMOUSE || ELEM(event->val, KM_RELEASE, KM_CLICK)) {
pie->block_radial->pie_data.flags |= UI_PIE_CLICK_STYLE;
pie->block_radial->pie_data.event = EVENT_NONE;
win->lock_pie_event = EVENT_NONE;
@@ -3285,7 +3317,7 @@ void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg)
UI_popup_block_invoke_ex(C, func, arg, NULL, WM_OP_INVOKE_DEFAULT);
}
-void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg)
+void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg, wmOperator *op)
{
wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *handle;
@@ -3294,6 +3326,7 @@ void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc po
handle->popup = true;
handle->retvalue = 1;
+ handle->popup_op = op;
handle->popup_arg = arg;
handle->popup_func = popup_func;
handle->cancel_func = cancel_func;
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index bdad667f206..3cc16f37736 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -303,7 +303,10 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_LOCAL:
if (id) {
- if (id_make_local(CTX_data_main(C), id, false, false)) {
+ Main *bmain = CTX_data_main(C);
+ if (id_make_local(bmain, id, false, false)) {
+ BKE_main_id_clear_newpoins(bmain);
+
/* reassign to get get proper updates/notifiers */
idptr = RNA_property_pointer_get(&template->ptr, template->prop);
RNA_property_pointer_set(&template->ptr, template->prop, idptr);
@@ -1975,6 +1978,7 @@ static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
case UICURVE_FUNC_HANDLE_AUTO_ANIM: /* set auto-clamped */
curvemap_handle_set(cuma, HD_AUTO_ANIM);
curvemapping_changed(cumap, false);
+ break;
case UICURVE_FUNC_EXTEND_HOZ: /* extend horiz */
cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
curvemapping_changed(cumap, false);
@@ -2837,7 +2841,7 @@ static void uilist_resize_update_cb(bContext *C, void *arg1, void *UNUSED(arg2))
uiListDyn *dyn_data = ui_list->dyn_data;
/* This way we get diff in number of additional items to show (positive) or hide (negative). */
- const int diff = iroundf((float)(dyn_data->resize - dyn_data->resize_prev) / (float)UI_UNIT_Y);
+ const int diff = round_fl_to_int((float)(dyn_data->resize - dyn_data->resize_prev) / (float)UI_UNIT_Y);
if (diff != 0) {
ui_list->list_grip += diff;
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 1d51c0588b6..1927d7280f3 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -120,17 +120,17 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) {
- UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE);
+ /* TEXTEDIT_UPDATE is usally used for search buttons. For these we also want
+ * the 'x' icon to clear search string, so setting VALUE_CLEAR flag, too. */
+ UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE | UI_BUT_VALUE_CLEAR);
}
break;
case PROP_POINTER:
{
- PointerRNA pptr;
-
- pptr = RNA_property_pointer_get(ptr, prop);
- if (!pptr.type)
- pptr.type = RNA_property_pointer_type(ptr, prop);
- icon = RNA_struct_ui_icon(pptr.type);
+ if (icon == 0) {
+ PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
+ icon = RNA_struct_ui_icon(pptr.type ? pptr.type : RNA_property_pointer_type(ptr, prop));
+ }
if (icon == ICON_DOT)
icon = 0;
@@ -265,7 +265,7 @@ int UI_icon_from_report_type(int type)
*/
int UI_calc_float_precision(int prec, double value)
{
- static const double pow10_neg[UI_PRECISION_FLOAT_MAX + 1] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7};
+ static const double pow10_neg[UI_PRECISION_FLOAT_MAX + 1] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6};
static const double max_pow = 10000000.0; /* pow(10, UI_PRECISION_FLOAT_MAX) */
BLI_assert(prec <= UI_PRECISION_FLOAT_MAX);
@@ -380,6 +380,17 @@ uiButStore *UI_butstore_create(uiBlock *block)
void UI_butstore_free(uiBlock *block, uiButStore *bs_handle)
{
+ /* Workaround for button store being moved into new block,
+ * which then can't use the previous buttons state ('ui_but_update_from_old_block' fails to find a match),
+ * keeping the active button in the old block holding a reference to the button-state in the new block: see T49034.
+ *
+ * Ideally we would manage moving the 'uiButStore', keeping a correct state.
+ * All things considered this is the most straightforward fix - Campbell.
+ */
+ if (block != bs_handle->block && bs_handle->block != NULL) {
+ block = bs_handle->block;
+ }
+
BLI_freelistN(&bs_handle->items);
BLI_remlink(&block->butstore, bs_handle);
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index c285d753b96..51bf09125ba 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -874,21 +874,18 @@ static void widget_draw_icon(
float ofs = 1.0f / aspect;
if (but->drawflag & UI_BUT_ICON_LEFT) {
- if (but->block->flag & UI_BLOCK_LOOP) {
- if (but->type == UI_BTYPE_SEARCH_MENU)
- xs = rect->xmin + 4.0f * ofs;
- else
- xs = rect->xmin + ofs;
- }
- else {
+ /* special case - icon_only pie buttons */
+ if (ui_block_is_pie_menu(but->block) && but->type != UI_BTYPE_MENU && but->str && but->str[0] == '\0')
+ xs = rect->xmin + 2.0f * ofs;
+ else if (but->dt == UI_EMBOSS_NONE || but->type == UI_BTYPE_LABEL)
+ xs = rect->xmin + 2.0f * ofs;
+ else
xs = rect->xmin + 4.0f * ofs;
- }
- ys = (rect->ymin + rect->ymax - height) / 2.0f;
}
else {
xs = (rect->xmin + rect->xmax - height) / 2.0f;
- ys = (rect->ymin + rect->ymax - height) / 2.0f;
}
+ ys = (rect->ymin + rect->ymax - height) / 2.0f;
/* force positions to integers, for zoom levels near 1. draws icons crisp. */
if (aspect > 0.95f && aspect < 1.05f) {
@@ -1508,10 +1505,10 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
/* draws text and icons for buttons */
static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
{
+ const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but);
const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
- uiButExtraIconType extra_icon_type;
ui_but_text_password_hide(password_str, but, false);
@@ -1554,11 +1551,15 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
/* Icons on the left with optional text label on the right */
else if (but->flag & UI_HAS_ICON || show_menu_icon) {
const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE;
- const float icon_size = ICON_SIZE_FROM_BUTRECT(rect);
+ const float icon_size = ICON_DEFAULT_WIDTH_SCALE;
/* menu item - add some more padding so menus don't feel cramped. it must
* be part of the button so that this area is still clickable */
- if (ui_block_is_menu(but->block))
+ if (ui_block_is_pie_menu(but->block)) {
+ if (but->dt == UI_EMBOSS_RADIAL)
+ rect->xmin += 0.3f * U.widget_unit;
+ }
+ else if (ui_block_is_menu(but->block))
rect->xmin += 0.3f * U.widget_unit;
widget_draw_icon(but, icon, alpha, rect, show_menu_icon);
@@ -1577,16 +1578,14 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
}
- /* unlink icon for this button type */
- if ((but->type == UI_BTYPE_SEARCH_MENU) &&
- ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
- {
+ /* extra icons, e.g. 'x' icon to clear text or icon for eyedropper */
+ if (extra_icon_type != UI_BUT_ICONEXTRA_NONE) {
rcti temp = *rect;
temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
- if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) {
- widget_draw_icon(but, ICON_X, alpha, &temp, false);
+ if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
+ widget_draw_icon(but, ICON_PANEL_CLOSE, alpha, &temp, false);
}
else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, false);
@@ -3656,11 +3655,15 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
switch (but->type) {
case UI_BTYPE_LABEL:
- if (but->block->flag & UI_BLOCK_LOOP)
- widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
- else {
- wt = widget_type(UI_WTYPE_LABEL);
- fstyle = &style->widgetlabel;
+ wt = widget_type(UI_WTYPE_LABEL);
+ fstyle = &style->widgetlabel;
+ if (but->drawflag & UI_BUT_BOX_ITEM) {
+ wt->wcol_theme = &tui->wcol_box;
+ wt->state = widget_state;
+ }
+ else if (but->block->flag & UI_BLOCK_LOOP) {
+ wt->wcol_theme = &tui->wcol_menu_back;
+ wt->state = widget_state;
}
break;
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 539284030c2..4b47d0da13e 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -2758,6 +2758,24 @@ void init_userdef_do_versions(void)
}
}
+ if (!USER_VERSION_ATLEAST(278, 6)) {
+ /* Clear preference flags for re-use. */
+ U.flag &= ~(
+ USER_FLAG_DEPRECATED_1 | USER_FLAG_DEPRECATED_2 | USER_FLAG_DEPRECATED_3 |
+ USER_FLAG_DEPRECATED_6 | USER_FLAG_DEPRECATED_7 |
+ USER_FLAG_DEPRECATED_9 | USER_FLAG_DEPRECATED_10);
+ U.uiflag &= ~(
+ USER_UIFLAG_DEPRECATED_7);
+ U.transopts &= ~(
+ USER_TR_DEPRECATED_2 | USER_TR_DEPRECATED_3 | USER_TR_DEPRECATED_4 |
+ USER_TR_DEPRECATED_6 | USER_TR_DEPRECATED_7);
+ U.gameflags &= ~(
+ USER_GL_RENDER_DEPRECATED_0 | USER_GL_RENDER_DEPRECATED_1 |
+ USER_GL_RENDER_DEPRECATED_3 | USER_GL_RENDER_DEPRECATED_4);
+
+ U.uiflag |= USER_LOCK_CURSOR_ADJUST;
+ }
+
/**
* Include next version bump.
*
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index c78d97ef86f..c704c4ae126 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -2138,6 +2138,14 @@ void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect
clamp_rctf_to_rcti(rect_dst, &rect_tmp);
}
+void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4])
+{
+ rctf mask;
+ unit_m4(matrix);
+ BLI_rctf_rcti_copy(&mask, &v2d->mask);
+ BLI_rctf_transform_calc_m4_pivot_min(&v2d->cur, &mask, matrix);
+}
+
bool UI_view2d_view_to_region_rcti_clip(View2D *v2d, const rctf *rect_src, rcti *rect_dst)
{
const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)};
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index d2b2f12c1a5..fa2c1f25cfc 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -447,7 +447,8 @@ static int view_scrolldown_exec(bContext *C, wmOperator *op)
RNA_int_set(op->ptr, "deltax", 0);
RNA_int_set(op->ptr, "deltay", -40);
- if (RNA_boolean_get(op->ptr, "page")) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "page");
+ if (RNA_property_is_set(op->ptr, prop) && RNA_property_boolean_get(op->ptr, prop)) {
ARegion *ar = CTX_wm_region(C);
RNA_int_set(op->ptr, "deltay", ar->v2d.mask.ymin - ar->v2d.mask.ymax);
}
@@ -497,7 +498,8 @@ static int view_scrollup_exec(bContext *C, wmOperator *op)
RNA_int_set(op->ptr, "deltax", 0);
RNA_int_set(op->ptr, "deltay", 40);
- if (RNA_boolean_get(op->ptr, "page")) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "page");
+ if (RNA_property_is_set(op->ptr, prop) && RNA_property_boolean_get(op->ptr, prop)) {
ARegion *ar = CTX_wm_region(C);
RNA_int_set(op->ptr, "deltay", BLI_rcti_size_y(&ar->v2d.mask));
}
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index a991f59e8e2..ca4ab30a08d 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -31,6 +31,9 @@
# include "BLI_winstuff.h"
#endif
+#include <string.h>
+#include <errno.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
@@ -102,12 +105,12 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
char filename[FILE_MAX];
RNA_string_get(op->ptr, "filepath", filename);
- const struct AlembicExportParams params = {
+ struct AlembicExportParams params = {
.frame_start = RNA_int_get(op->ptr, "start"),
.frame_end = RNA_int_get(op->ptr, "end"),
- .frame_step_xform = 1.0 / (double)RNA_int_get(op->ptr, "xsamples"),
- .frame_step_shape = 1.0 / (double)RNA_int_get(op->ptr, "gsamples"),
+ .frame_samples_xform = RNA_int_get(op->ptr, "xsamples"),
+ .frame_samples_shape = RNA_int_get(op->ptr, "gsamples"),
.shutter_open = RNA_float_get(op->ptr, "sh_open"),
.shutter_close = RNA_float_get(op->ptr, "sh_close"),
@@ -122,24 +125,37 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
.renderable_only = RNA_boolean_get(op->ptr, "renderable_only"),
.face_sets = RNA_boolean_get(op->ptr, "face_sets"),
.use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"),
+ .export_hair = RNA_boolean_get(op->ptr, "export_hair"),
+ .export_particles = RNA_boolean_get(op->ptr, "export_particles"),
.compression_type = RNA_enum_get(op->ptr, "compression_type"),
.packuv = RNA_boolean_get(op->ptr, "packuv"),
- .triangulate = RNA_boolean_get(op->ptr, "triangulate"),
- .quad_method = RNA_enum_get(op->ptr, "quad_method"),
- .ngon_method = RNA_enum_get(op->ptr, "ngon_method"),
+ .triangulate = RNA_boolean_get(op->ptr, "triangulate"),
+ .quad_method = RNA_enum_get(op->ptr, "quad_method"),
+ .ngon_method = RNA_enum_get(op->ptr, "ngon_method"),
.global_scale = RNA_float_get(op->ptr, "global_scale"),
};
- ABC_export(CTX_data_scene(C), C, filename, &params);
+ /* Take some defaults from the scene, if not specified explicitly. */
+ Scene *scene = CTX_data_scene(C);
+ if (params.frame_start == INT_MIN) {
+ params.frame_start = SFRA;
+ }
+ if (params.frame_end == INT_MIN) {
+ params.frame_end = EFRA;
+ }
+
+ const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job");
+ bool ok = ABC_export(scene, C, filename, &params, as_background_job);
- return OPERATOR_FINISHED;
+ return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
{
uiLayout *box;
uiLayout *row;
+ uiLayout *col;
#ifdef WITH_ALEMBIC_HDF5
box = uiLayoutBox(layout);
@@ -231,6 +247,15 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
row = uiLayoutRow(box, false);
uiLayoutSetEnabled(row, triangulate);
uiItemR(row, imfptr, "ngon_method", 0, NULL, ICON_NONE);
+
+ /* Object Data */
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Particle Systems:"), ICON_PARTICLE_DATA);
+
+ col = uiLayoutColumn(box, true);
+ uiItemR(col, imfptr, "export_hair", 0, NULL, ICON_NONE);
+ uiItemR(col, imfptr, "export_particles", 0, NULL, ICON_NONE);
}
static void wm_alembic_export_draw(bContext *C, wmOperator *op)
@@ -282,11 +307,17 @@ void WM_OT_alembic_export(wmOperatorType *ot)
FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
- RNA_def_int(ot->srna, "start", 1, INT_MIN, INT_MAX,
- "Start Frame", "Start Frame", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "start", INT_MIN, INT_MIN, INT_MAX,
+ "Start Frame",
+ "Start frame of the export, use the default value to "
+ "take the start frame of the current scene",
+ INT_MIN, INT_MAX);
- RNA_def_int(ot->srna, "end", 1, INT_MIN, INT_MAX,
- "End Frame", "End Frame", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "end", INT_MIN, INT_MIN, INT_MAX,
+ "End Frame",
+ "End frame of the export, use the default value to "
+ "take the end frame of the current scene",
+ INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "xsamples", 1, 1, 128,
"Transform Samples", "Number of times per frame transformations are sampled", 1, 128);
@@ -348,9 +379,15 @@ void WM_OT_alembic_export(wmOperatorType *ot)
RNA_def_enum(ot->srna, "ngon_method", rna_enum_modifier_triangulate_quad_method_items,
MOD_TRIANGULATE_NGON_BEAUTY, "Polygon Method", "Method for splitting the polygons into triangles");
+ RNA_def_boolean(ot->srna, "export_hair", 1, "Export Hair", "Exports hair particle systems as animated curves");
+ RNA_def_boolean(ot->srna, "export_particles", 1, "Export Particles", "Exports non-hair particle systems");
+
+ RNA_def_boolean(ot->srna, "as_background_job", true, "Run as Background Job",
+ "Enable this to run the import in the background, disable to block Blender while importing");
+
/* This dummy prop is used to check whether we need to init the start and
- * end frame values to that of the scene's, otherwise they are reset at
- * every change, draw update. */
+ * end frame values to that of the scene's, otherwise they are reset at
+ * every change, draw update. */
RNA_def_boolean(ot->srna, "init_scene_frame_range", false, "", "");
}
@@ -383,9 +420,20 @@ static int get_sequence_len(char *filename, int *ofs)
}
char path[FILE_MAX];
+ BLI_path_abs(filename, G.main->name);
BLI_split_dir_part(filename, path, FILE_MAX);
+ if (path[0] == '\0') {
+ /* The filename had no path, so just use the blend file path. */
+ BLI_split_dir_part(G.main->name, path, FILE_MAX);
+ }
+
DIR *dir = opendir(path);
+ if (dir == NULL) {
+ fprintf(stderr, "Error opening directory '%s': %s\n",
+ path, errno ? strerror(errno) : "unknown error");
+ return -1;
+ }
const char *ext = ".abc";
const char *basename = BLI_path_basename(filename);
@@ -482,17 +530,24 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op)
const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence");
const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range");
const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
+ const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job");
int offset = 0;
int sequence_len = 1;
if (is_sequence) {
sequence_len = get_sequence_len(filename, &offset);
+ if (sequence_len < 0) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to determine ABC sequence length");
+ return OPERATOR_CANCELLED;
+ }
}
- ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes);
+ bool ok = ABC_import(C, filename, scale, is_sequence, set_frame_range,
+ sequence_len, offset, validate_meshes,
+ as_background_job);
- return OPERATOR_FINISHED;
+ return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void WM_OT_alembic_import(wmOperatorType *ot)
@@ -523,6 +578,9 @@ void WM_OT_alembic_import(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "is_sequence", false, "Is Sequence",
"Set to true if the cache is split into separate files");
+
+ RNA_def_boolean(ot->srna, "as_background_job", true, "Run as Background Job",
+ "Enable this to run the export in the background, disable to block Blender while exporting");
}
#endif
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index ebe8898571d..975bbddd893 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -93,26 +93,28 @@ static int cachefile_open_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
- CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename));
+ CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename), 0);
BLI_strncpy(cache_file->filepath, filename, FILE_MAX);
BKE_cachefile_reload(bmain, cache_file);
- /* hook into UI */
- PropertyPointerRNA *pprop = op->customdata;
-
- if (pprop->prop) {
- /* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
- id_us_min(&cache_file->id);
-
- PointerRNA idptr;
- RNA_id_pointer_create(&cache_file->id, &idptr);
- RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
- RNA_property_update(C, &pprop->ptr, pprop->prop);
+ /* Will be set when running invoke, not exec directly. */
+ if (op->customdata != NULL) {
+ /* hook into UI */
+ PropertyPointerRNA *pprop = op->customdata;
+ if (pprop->prop) {
+ /* when creating new ID blocks, use is already 1, but RNA
+ * pointer se also increases user, so this compensates it */
+ id_us_min(&cache_file->id);
+
+ PointerRNA idptr;
+ RNA_id_pointer_create(&cache_file->id, &idptr);
+ RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
+ RNA_property_update(C, &pprop->ptr, pprop->prop);
+ }
+
+ MEM_freeN(op->customdata);
}
- MEM_freeN(op->customdata);
-
return OPERATOR_FINISHED;
}
@@ -143,7 +145,7 @@ static int cachefile_reload_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
- BLI_listbase_clear(&cache_file->object_paths);
+ BLI_freelistN(&cache_file->object_paths);
BKE_cachefile_reload(bmain, cache_file);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index baae92f962e..cead08afd61 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -87,8 +87,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int include_shapekeys;
int deform_bones_only;
- int include_uv_textures;
- int include_material_textures;
+ int export_texture_type;
int use_texture_copies;
int active_uv_only;
@@ -97,7 +96,10 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int use_blender_profile;
int sort_by_name;
int export_transformation_type;
+
int open_sim;
+ int limit_precision;
+ int keep_bind_info;
int export_count;
@@ -136,8 +138,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
include_shapekeys = RNA_boolean_get(op->ptr, "include_shapekeys");
deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only");
- include_uv_textures = RNA_boolean_get(op->ptr, "include_uv_textures");
- include_material_textures = RNA_boolean_get(op->ptr, "include_material_textures");
+ export_texture_type = RNA_enum_get(op->ptr, "export_texture_type_selection");
use_texture_copies = RNA_boolean_get(op->ptr, "use_texture_copies");
active_uv_only = RNA_boolean_get(op->ptr, "active_uv_only");
@@ -148,6 +149,9 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection");
open_sim = RNA_boolean_get(op->ptr, "open_sim");
+ limit_precision = RNA_boolean_get(op->ptr, "limit_precision");
+ keep_bind_info = RNA_boolean_get(op->ptr, "keep_bind_info");
+
/* get editmode results */
ED_object_editmode_load(CTX_data_edit_object(C));
@@ -163,8 +167,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
deform_bones_only,
active_uv_only,
- include_uv_textures,
- include_material_textures,
+ export_texture_type,
use_texture_copies,
triangulate,
@@ -172,7 +175,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
use_blender_profile,
sort_by_name,
export_transformation_type,
- open_sim);
+
+ open_sim,
+ limit_precision,
+ keep_bind_info
+ );
if (export_count == 0) {
BKE_report(op->reports, RPT_WARNING, "No objects selected -- Created empty export file");
@@ -231,10 +238,7 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(row, imfptr, "active_uv_only", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "include_uv_textures", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "include_material_textures", 0, NULL, ICON_NONE);
+ uiItemR(row, imfptr, "export_texture_type_selection", 0, "", ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "use_texture_copies", 1, NULL, ICON_NONE);
@@ -256,11 +260,11 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemL(row, IFACE_("Collada Options:"), ICON_MODIFIER);
row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE);
+ uiItemR(row, imfptr, "triangulate", 1, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "use_object_instantiation", 0, NULL, ICON_NONE);
+ uiItemR(row, imfptr, "use_object_instantiation", 1, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "use_blender_profile", 0, NULL, ICON_NONE);
+ uiItemR(row, imfptr, "use_blender_profile", 1, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
@@ -270,6 +274,12 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "keep_bind_info", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "limit_precision", 0, NULL, ICON_NONE);
+
}
static void wm_collada_export_draw(bContext *UNUSED(C), wmOperator *op)
@@ -296,6 +306,8 @@ static bool wm_collada_export_check(bContext *UNUSED(C), wmOperator *op)
void WM_OT_collada_export(wmOperatorType *ot)
{
+ struct StructRNA *func = ot->srna;
+
static EnumPropertyItem prop_bc_export_mesh_type[] = {
{BC_MESH_TYPE_VIEW, "view", 0, "View", "Apply modifier's view settings"},
{BC_MESH_TYPE_RENDER, "render", 0, "Render", "Apply modifier's render settings"},
@@ -303,9 +315,15 @@ void WM_OT_collada_export(wmOperatorType *ot)
};
static EnumPropertyItem prop_bc_export_transformation_type[] = {
- {BC_TRANSFORMATION_TYPE_MATRIX, "matrix", 0, "Matrix", "Use <matrix> to specify transformations"},
- {BC_TRANSFORMATION_TYPE_TRANSROTLOC, "transrotloc", 0, "TransRotLoc", "Use <translate>, <rotate>, <scale> to specify transformations"},
- {0, NULL, 0, NULL, NULL}
+ { BC_TRANSFORMATION_TYPE_MATRIX, "matrix", 0, "Matrix", "Use <matrix> to specify transformations" },
+ { BC_TRANSFORMATION_TYPE_TRANSROTLOC, "transrotloc", 0, "TransRotLoc", "Use <translate>, <rotate>, <scale> to specify transformations" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ static EnumPropertyItem prop_bc_export_texture_type[] = {
+ { BC_TEXTURE_TYPE_MAT, "mat", 0, "Materials", "Export Materials" },
+ { BC_TEXTURE_TYPE_UV, "uv", 0, "UV Textures", "Export UV Textures (Face textures) as materials" },
+ { 0, NULL, 0, NULL, NULL }
};
ot->name = "Export COLLADA";
@@ -325,65 +343,74 @@ void WM_OT_collada_export(wmOperatorType *ot)
ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_SAVE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
- RNA_def_boolean(ot->srna,
+ RNA_def_boolean(func,
"apply_modifiers", 0, "Apply Modifiers",
"Apply modifiers to exported mesh (non destructive))");
- RNA_def_int(ot->srna, "export_mesh_type", 0, INT_MIN, INT_MAX,
+ RNA_def_int(func, "export_mesh_type", 0, INT_MIN, INT_MAX,
"Resolution", "Modifier resolution for export", INT_MIN, INT_MAX);
- RNA_def_enum(ot->srna, "export_mesh_type_selection", prop_bc_export_mesh_type, 0,
+ RNA_def_enum(func, "export_mesh_type_selection", prop_bc_export_mesh_type, 0,
"Resolution", "Modifier resolution for export");
- RNA_def_boolean(ot->srna, "selected", 0, "Selection Only",
+ RNA_def_boolean(func, "selected", 0, "Selection Only",
"Export only selected elements");
- RNA_def_boolean(ot->srna, "include_children", 0, "Include Children",
+ RNA_def_boolean(func, "include_children", 0, "Include Children",
"Export all children of selected objects (even if not selected)");
- RNA_def_boolean(ot->srna, "include_armatures", 0, "Include Armatures",
+ RNA_def_boolean(func, "include_armatures", 0, "Include Armatures",
"Export related armatures (even if not selected)");
- RNA_def_boolean(ot->srna, "include_shapekeys", 1, "Include Shape Keys",
+ RNA_def_boolean(func, "include_shapekeys", 1, "Include Shape Keys",
"Export all Shape Keys from Mesh Objects");
- RNA_def_boolean(ot->srna, "deform_bones_only", 0, "Deform Bones only",
+ RNA_def_boolean(func, "deform_bones_only", 0, "Deform Bones only",
"Only export deforming bones with armatures");
-
- RNA_def_boolean(ot->srna, "active_uv_only", 0, "Only Selected UV Map",
+ RNA_def_boolean(func, "active_uv_only", 0, "Only Selected UV Map",
"Export only the selected UV Map");
- RNA_def_boolean(ot->srna, "include_uv_textures", 0, "Include UV Textures",
- "Export textures assigned to the object UV Maps");
-
- RNA_def_boolean(ot->srna, "include_material_textures", 0, "Include Material Textures",
- "Export textures assigned to the object Materials");
-
- RNA_def_boolean(ot->srna, "use_texture_copies", 1, "Copy",
+ RNA_def_boolean(func, "use_texture_copies", 1, "Copy",
"Copy textures to same folder where the .dae file is exported");
- RNA_def_boolean(ot->srna, "triangulate", 1, "Triangulate",
+ RNA_def_boolean(func, "triangulate", 1, "Triangulate",
"Export Polygons (Quads & NGons) as Triangles");
- RNA_def_boolean(ot->srna, "use_object_instantiation", 1, "Use Object Instances",
+ RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances",
"Instantiate multiple Objects from same Data");
- RNA_def_boolean(ot->srna, "use_blender_profile", 1, "Use Blender Profile",
+ RNA_def_boolean(func, "use_blender_profile", 1, "Use Blender Profile",
"Export additional Blender specific information (for material, shaders, bones, etc.)");
- RNA_def_boolean(ot->srna, "sort_by_name", 0, "Sort by Object name",
+ RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name",
"Sort exported data by Object name");
- RNA_def_int(ot->srna, "export_transformation_type", 0, INT_MIN, INT_MAX,
- "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
- RNA_def_enum(ot->srna, "export_transformation_type_selection", prop_bc_export_transformation_type, 0,
- "Transform", "Transformation type for translation, scale and rotation");
+ RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX,
+ "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
+
+ RNA_def_enum(func, "export_transformation_type_selection", prop_bc_export_transformation_type, 0,
+ "Transform", "Transformation type for translation, scale and rotation");
- RNA_def_boolean(ot->srna, "open_sim", 0, "Export to SL/OpenSim",
+
+ RNA_def_int(func, "export_texture_type", 0, INT_MIN, INT_MAX,
+ "Texture Type", "Type for exported Textures (UV or MAT)", INT_MIN, INT_MAX);
+
+ RNA_def_enum(func, "export_texture_type_selection", prop_bc_export_texture_type, 0,
+ "Texture Type", "Type for exported Textures (UV or MAT)");
+
+
+ RNA_def_boolean(func, "open_sim", 0, "Export to SL/OpenSim",
"Compatibility mode for SL, OpenSim and other compatible online worlds");
+
+ RNA_def_boolean(func, "limit_precision", 0,
+ "Limit Precision", "Reduce the precision of the exported data to 6 digits");
+
+ RNA_def_boolean(func, "keep_bind_info", 0,
+ "Keep Bind Info", "Store Bindpose information in custom bone properties for later use during Collada export");
+
}
@@ -395,7 +422,9 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
int find_chains;
int auto_connect;
int fix_orientation;
- int min_chain_length;
+ int min_chain_length;
+
+ int keep_bind_info;
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
@@ -407,6 +436,9 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
find_chains = RNA_boolean_get(op->ptr, "find_chains");
auto_connect = RNA_boolean_get(op->ptr, "auto_connect");
fix_orientation = RNA_boolean_get(op->ptr, "fix_orientation");
+
+ keep_bind_info = RNA_boolean_get(op->ptr, "keep_bind_info");
+
min_chain_length = RNA_int_get(op->ptr, "min_chain_length");
RNA_string_get(op->ptr, "filepath", filename);
@@ -416,7 +448,8 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
find_chains,
auto_connect,
fix_orientation,
- min_chain_length))
+ min_chain_length,
+ keep_bind_info) )
{
return OPERATOR_FINISHED;
}
@@ -453,6 +486,13 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr)
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "min_chain_length", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "keep_bind_info", 0, NULL, ICON_NONE);
+
}
static void wm_collada_import_draw(bContext *UNUSED(C), wmOperator *op)
@@ -508,5 +548,9 @@ void WM_OT_collada_import(wmOperatorType *ot)
0,
INT_MAX);
+ RNA_def_boolean(ot->srna,
+ "keep_bind_info", 0, "Keep Bind Info",
+ "Store Bindpose information in custom bone properties for later use during Collada export");
+
}
#endif
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index e3e8f35e7d8..69335195b96 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -770,15 +770,19 @@ static int create_primitive_from_points(bContext *C, wmOperator *op, const float
new_spline = BKE_mask_spline_add(mask_layer);
new_spline->flag = MASK_SPLINE_CYCLIC | SELECT;
- new_spline->tot_point = num_points;
new_spline->points = MEM_recallocN(new_spline->points,
- sizeof(MaskSplinePoint) * new_spline->tot_point);
+ sizeof(MaskSplinePoint) * num_points);
mask_layer->act_spline = new_spline;
mask_layer->act_point = NULL;
+ const int spline_index = BKE_mask_layer_shape_spline_to_index(mask_layer, new_spline);
+
for (i = 0; i < num_points; i++) {
+ new_spline->tot_point = i + 1;
+
MaskSplinePoint *new_point = &new_spline->points[i];
+ BKE_mask_parent_init(&new_point->parent);
copy_v2_v2(new_point->bezt.vec[1], points[i]);
mul_v2_fl(new_point->bezt.vec[1], scale);
@@ -787,6 +791,12 @@ static int create_primitive_from_points(bContext *C, wmOperator *op, const float
new_point->bezt.h1 = handle_type;
new_point->bezt.h2 = handle_type;
BKE_mask_point_select_set(new_point, true);
+
+ if (mask_layer->splines_shapes.first) {
+ BKE_mask_layer_shape_changed_add(mask_layer,
+ spline_index + i,
+ true, true);
+ }
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 2b4f94a37ef..be7eb2bf9ed 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -834,13 +834,12 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar,
/* apply transformation so mask editing tools will assume drawing from the origin in normalized space */
glPushMatrix();
-
+ glTranslatef(x + xofs, y + yofs, 0);
+ glScalef(zoomx, zoomy, 0);
if (stabmat) {
glMultMatrixf(stabmat);
}
-
- glTranslatef(x + xofs, y + yofs, 0);
- glScalef(maxdim * zoomx, maxdim * zoomy, 0);
+ glScalef(maxdim, maxdim, 0);
if (do_draw_cb) {
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index eef03852007..196285cf02a 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -889,7 +889,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
data->is_accurate = (event->val == KM_PRESS);
- /* fall-through */ /* update CV position */
+ ATTR_FALLTHROUGH; /* update CV position */
case MOUSEMOVE:
{
ScrArea *sa = CTX_wm_area(C);
@@ -999,7 +999,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (weight) {
sub_v2_v2v2(c, offco, p);
- project_v2_v2v2(vec, c, no);
+ project_v2_v2v2_normalized(vec, c, no);
w = len_v2(vec);
@@ -1376,7 +1376,7 @@ static int slide_spline_curvature_modal(bContext *C, wmOperator *op, const wmEve
}
- /* fall-through */ /* update CV position */
+ ATTR_FALLTHROUGH; /* update CV position */
case MOUSEMOVE:
{
float B[2], mouse_coord[2], delta[2];
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index c4e87614732..6c6c106b19a 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -306,31 +306,30 @@ void paintface_deselect_all_visible(Object *ob, int action, bool flush_flags)
bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
{
- Mesh *me;
- MPoly *mp;
- MTexPoly *tf;
- MLoop *ml;
- MVert *mvert;
+ const Mesh *me;
+ const MPoly *mp;
+ const MLoop *ml;
+ const MVert *mvert;
int a, b;
bool ok = false;
float vec[3], bmat[3][3];
me = BKE_mesh_from_object(ob);
- if (!me || !me->mtpoly) return ok;
+ if (!me || !me->mloopuv) {
+ return ok;
+ }
copy_m3_m4(bmat, ob->obmat);
mvert = me->mvert;
mp = me->mpoly;
- tf = me->mtpoly;
- for (a = me->totpoly; a > 0; a--, mp++, tf++) {
+ for (a = me->totpoly; a > 0; a--, mp++) {
if (mp->flag & ME_HIDE || !(mp->flag & ME_FACE_SEL))
continue;
ml = me->mloop + mp->totloop;
for (b = 0; b < mp->totloop; b++, ml++) {
- copy_v3_v3(vec, (mvert[ml->v].co));
- mul_m3_v3(bmat, vec);
+ mul_v3_m3v3(vec, bmat, mvert[ml->v].co);
add_v3_v3v3(vec, vec, ob->obmat[3]);
minmax_v3v3_v3(r_min, r_max, vec);
}
@@ -798,25 +797,47 @@ void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTop
qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort);
- /* Since the loop starts at 2, we must define the last index where the hash's differ */
- last = ((totvert >= 2) && (topo_pairs[0].hash == topo_pairs[1].hash)) ? 0 : 1;
+ last = 0;
/* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2,
* but you cant ever access the last 'a' index of MirrTopoPairs */
- for (a = 2; a <= totvert; a++) {
- /* printf("I %d %ld %d\n", (a-last), MirrTopoPairs[a ].hash, MirrTopoPairs[a ].v_index ); */
- if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
- if (a - last == 2) {
- if (em) {
- index_lookup[topo_pairs[a - 1].v_index] = (intptr_t)BM_vert_at_index(em->bm, topo_pairs[a - 2].v_index);
- index_lookup[topo_pairs[a - 2].v_index] = (intptr_t)BM_vert_at_index(em->bm, topo_pairs[a - 1].v_index);
+ if (em) {
+ BMVert **vtable = em->bm->vtable;
+ for (a = 1; a <= totvert; a++) {
+ /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */
+ if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
+ const int match_count = a - last;
+ if (match_count == 2) {
+ const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
+ index_lookup[j] = (intptr_t)vtable[k];
+ index_lookup[k] = (intptr_t)vtable[j];
+ }
+ else if (match_count == 1) {
+ /* Center vertex. */
+ const int j = topo_pairs[a - 1].v_index;
+ index_lookup[j] = (intptr_t)vtable[j];
+ }
+ last = a;
+ }
+ }
+ }
+ else {
+ /* same as above, for mesh */
+ for (a = 1; a <= totvert; a++) {
+ if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
+ const int match_count = a - last;
+ if (match_count == 2) {
+ const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
+ index_lookup[j] = k;
+ index_lookup[k] = j;
}
- else {
- index_lookup[topo_pairs[a - 1].v_index] = topo_pairs[a - 2].v_index;
- index_lookup[topo_pairs[a - 2].v_index] = topo_pairs[a - 1].v_index;
+ else if (match_count == 1) {
+ /* Center vertex. */
+ const int j = topo_pairs[a - 1].v_index;
+ index_lookup[j] = j;
}
+ last = a;
}
- last = a;
}
}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 3725590c188..77772cfc8cc 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -233,7 +233,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_circle segments=%i diameter=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b",
+ "create_circle segments=%i radius=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
cap_end, cap_tri, mat, calc_uvs))
{
@@ -384,7 +384,7 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
RNA_def_float_distance(ot->srna, "radius1", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 1", "", 0.001, 100.00);
- RNA_def_float_distance(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.001, 100.00);
+ RNA_def_float_distance(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.0, 100.00);
RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", "");
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index a81add7a86e..6b4f3516338 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -150,6 +150,7 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
for (i = 0; i < NUM_VALUE_KINDS; i++) {
opdata->shift_value[i] = -1.0f;
+ opdata->initial_length[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;
@@ -300,7 +301,7 @@ static void edbm_bevel_calc_initial_length(wmOperator *op, const wmEvent *event,
mlen[1] = opdata->mcenter[1] - event->mval[1];
len = len_v2(mlen);
vmode = opdata->value_mode;
- if (mode_changed) {
+ if (mode_changed || opdata->initial_length[vmode] == -1.0f) {
/* 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 */
@@ -506,6 +507,8 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
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);
+ if (opdata->initial_length[opdata->value_mode] == -1.0f)
+ edbm_bevel_calc_initial_length(op, event, true);
}
/* Update offset accordingly to new offset_type. */
if (!has_numinput &&
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 0e1ba2b1c25..3a9e278f039 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -73,6 +73,7 @@ static bool mesh_bisect_interactive_calc(
wmGesture *gesture = op->customdata;
BisectData *opdata;
+ View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
@@ -101,7 +102,7 @@ static bool mesh_bisect_interactive_calc(
normalize_v3(plane_no); /* not needed but nicer for user */
/* point on plane, can use either start or endpoint */
- ED_view3d_win_to_3d(ar, co_ref, co_a_ss, plane_co);
+ ED_view3d_win_to_3d(v3d, ar, co_ref, co_a_ss, plane_co);
if (opdata->is_first == false)
EDBM_redo_state_restore(opdata->mesh_backup, em, false);
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index d4c49833c2c..5ac90ec29e6 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -506,40 +506,46 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
ViewContext vc;
BMVert *v1;
BMIter iter;
- float min[3], max[3];
- bool done = false;
+ float center[3];
+ uint verts_len;
bool use_proj;
em_setup_viewcontext(C, &vc);
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
(vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
- INIT_MINMAX(min, max);
+ zero_v3(center);
+ verts_len = 0;
BM_ITER_MESH (v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) {
- minmax_v3v3_v3(min, max, v1->co);
- done = true;
+ add_v3_v3(center, v1->co);
+ verts_len += 1;
}
}
/* call extrude? */
- if (done) {
+ if (verts_len != 0) {
const char extrude_htype = edbm_extrude_htype_from_em_select(vc.em);
const bool rot_src = RNA_boolean_get(op->ptr, "rotate_source");
BMEdge *eed;
- float vec[3], cent[3], mat[3][3];
+ float mat[3][3];
+ float vec[3], ofs[3];
float nor[3] = {0.0, 0.0, 0.0};
/* 2D normal calc */
const float mval_f[2] = {(float)event->mval[0],
(float)event->mval[1]};
+ mul_v3_fl(center, 1.0f / (float)verts_len);
+
/* check for edges that are half selected, use for rotation */
- done = false;
+ bool done = false;
BM_ITER_MESH (eed, &iter, vc.em->bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
float co1[2], co2[2];
@@ -580,21 +586,20 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
}
/* center */
- mid_v3_v3v3(cent, min, max);
- copy_v3_v3(min, cent);
+ copy_v3_v3(ofs, center);
- mul_m4_v3(vc.obedit->obmat, min); /* view space */
- ED_view3d_win_to_3d_int(vc.ar, min, event->mval, min);
- mul_m4_v3(vc.obedit->imat, min); // back in object space
+ mul_m4_v3(vc.obedit->obmat, ofs); /* view space */
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, ofs, event->mval, ofs);
+ mul_m4_v3(vc.obedit->imat, ofs); // back in object space
- sub_v3_v3(min, cent);
+ sub_v3_v3(ofs, center);
/* calculate rotation */
unit_m3(mat);
if (done) {
float angle;
- normalize_v3_v3(vec, min);
+ normalize_v3_v3(vec, ofs);
angle = angle_normalized_v3v3(vec, nor);
@@ -614,7 +619,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
if (rot_src) {
EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3",
- BM_ELEM_SELECT, cent, mat);
+ BM_ELEM_SELECT, center, mat);
/* also project the source, for retopo workflow */
if (use_proj)
@@ -623,22 +628,21 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, true, true);
EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3",
- BM_ELEM_SELECT, cent, mat);
+ BM_ELEM_SELECT, center, mat);
EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v",
- BM_ELEM_SELECT, min);
+ BM_ELEM_SELECT, ofs);
}
else {
- const float *curs = ED_view3d_cursor3d_get(vc.scene, vc.v3d);
+ const float *cursor = ED_view3d_cursor3d_get(vc.scene, vc.v3d);
BMOperator bmop;
BMOIter oiter;
-
- copy_v3_v3(min, curs);
- ED_view3d_win_to_3d_int(vc.ar, min, event->mval, min);
- invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
- mul_m4_v3(vc.obedit->imat, min); // back in object space
+ copy_v3_v3(center, cursor);
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
+
+ mul_m4_v3(vc.obedit->imat, center); // back in object space
- EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", min);
+ EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", center);
BMO_op_exec(vc.em->bm, &bmop);
BMO_ITER (v1, &oiter, bmop.slots_out, "vert.out", BM_VERT) {
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index de93211bec4..49bfde77032 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -51,6 +51,7 @@
#include "mesh_intern.h" /* own include */
#include "tools/bmesh_intersect.h"
+#include "tools/bmesh_separate.h"
/* detect isolated holes and fill them */
@@ -137,6 +138,12 @@ enum {
ISECT_SEL_UNSEL = 1,
};
+enum {
+ ISECT_SEPARATE_ALL = 0,
+ ISECT_SEPARATE_CUT = 1,
+ ISECT_SEPARATE_NONE = 2,
+};
+
static int edbm_intersect_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -144,7 +151,9 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
BMesh *bm = em->bm;
const int mode = RNA_enum_get(op->ptr, "mode");
int (*test_fn)(BMFace *, void *);
- bool use_separate = RNA_boolean_get(op->ptr, "use_separate");
+ bool use_separate_all = false;
+ bool use_separate_cut = false;
+ const int separate_mode = RNA_enum_get(op->ptr, "separate_mode");
const float eps = RNA_float_get(op->ptr, "threshold");
bool use_self;
bool has_isect;
@@ -160,15 +169,38 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
break;
}
+ switch (separate_mode) {
+ case ISECT_SEPARATE_ALL:
+ use_separate_all = true;
+ break;
+ case ISECT_SEPARATE_CUT:
+ if (use_self == false) {
+ use_separate_cut = true;
+ }
+ else {
+ /* we could support this but would require more advanced logic inside 'BM_mesh_intersect'
+ * for now just separate all */
+ use_separate_all = true;
+ }
+ break;
+ default: /* ISECT_SEPARATE_NONE */
+ break;
+ }
has_isect = BM_mesh_intersect(
bm,
em->looptris, em->tottri,
test_fn, NULL,
- use_self, use_separate, true, true,
+ use_self, use_separate_all, true, true, true,
-1,
eps);
+ if (use_separate_cut) {
+ /* detach selected/un-selected faces */
+ BM_mesh_separate_faces(
+ bm,
+ BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT));
+ }
if (has_isect) {
edbm_intersect_select(em);
@@ -190,6 +222,16 @@ void MESH_OT_intersect(struct wmOperatorType *ot)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem isect_separate_items[] = {
+ {ISECT_SEPARATE_ALL, "ALL", 0, "All",
+ "Separate all geometry from intersections"},
+ {ISECT_SEPARATE_CUT, "CUT", 0, "Cut",
+ "Cut into geometry keeping each side separate (Selected/Unselected only)"},
+ {ISECT_SEPARATE_NONE, "NONE", 0, "Merge",
+ "Merge all geometry from the intersection"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Intersect (Knife)";
ot->description = "Cut an intersection into faces";
@@ -201,7 +243,7 @@ void MESH_OT_intersect(struct wmOperatorType *ot)
/* props */
RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", "");
- RNA_def_boolean(ot->srna, "use_separate", true, "Separate", "");
+ RNA_def_enum(ot->srna, "separate_mode", isect_separate_items, ISECT_SEPARATE_CUT, "Separate Mode", "");
RNA_def_float_distance(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001);
/* flags */
@@ -239,7 +281,7 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
bm,
em->looptris, em->tottri,
test_fn, NULL,
- false, false, true, true,
+ false, false, true, true, true,
boolean_operation,
eps);
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index a84b8d9dcc8..69e8fa03d72 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -971,7 +971,7 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
copy_v3_v3(co_depth, kcd->prev.cage);
mul_m4_v3(kcd->ob->obmat, co_depth);
- ED_view3d_win_to_3d(kcd->ar, co_depth, kcd->curr.mval, curr_cage_adjust);
+ ED_view3d_win_to_3d(kcd->vc.v3d, kcd->ar, co_depth, kcd->curr.mval, curr_cage_adjust);
mul_m4_v3(kcd->ob->imat, curr_cage_adjust);
sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage);
@@ -1206,6 +1206,7 @@ static bool knife_ray_intersect_face(
for (; tri_i < tottri; tri_i++) {
const float *lv1, *lv2, *lv3;
+ float ray_tri_uv[2];
tri = kcd->em->looptris[tri_i];
if (tri[0]->f != f)
@@ -1217,7 +1218,7 @@ static bool knife_ray_intersect_face(
* tesselation edge and might not hit either tesselation tri with
* an exact test;
* we will exclude hits near real edges by a later test */
- if (isect_ray_tri_epsilon_v3(v1, raydir, lv1, lv2, lv3, &lambda, NULL, KNIFE_FLT_EPS)) {
+ if (isect_ray_tri_epsilon_v3(v1, raydir, lv1, lv2, lv3, &lambda, ray_tri_uv, KNIFE_FLT_EPS)) {
/* check if line coplanar with tri */
normal_tri_v3(tri_norm, lv1, lv2, lv3);
plane_from_point_normal_v3(tri_plane, lv1, tri_norm);
@@ -1226,8 +1227,7 @@ static bool knife_ray_intersect_face(
{
return false;
}
- copy_v3_v3(hit_cageco, v1);
- madd_v3_v3fl(hit_cageco, raydir, lambda);
+ interp_v3_v3v3v3_uv(hit_cageco, lv1, lv2, lv3, ray_tri_uv);
/* Now check that far enough away from verts and edges */
lst = knife_get_face_kedges(kcd, f);
for (ref = lst->first; ref; ref = ref->next) {
@@ -1239,11 +1239,7 @@ static bool knife_ray_intersect_face(
return false;
}
}
-
- transform_point_by_tri_v3(
- hit_co, hit_cageco,
- tri[0]->v->co, tri[1]->v->co, tri[2]->v->co,
- lv1, lv2, lv3);
+ interp_v3_v3v3v3_uv(hit_co, tri[0]->v->co, tri[1]->v->co, tri[2]->v->co, ray_tri_uv);
return true;
}
}
@@ -1472,7 +1468,7 @@ static void clip_to_ortho_planes(float v1[3], float v2[3], const float center[3]
/* could be v1 or v2 */
sub_v3_v3(v1, center);
- project_plane_v3_v3v3(closest, v1, dir);
+ project_plane_normalized_v3_v3v3(closest, v1, dir);
add_v3_v3(closest, center);
madd_v3_v3v3fl(v1, closest, dir, d);
@@ -2140,7 +2136,7 @@ static float snap_v2_angle(float r[2], const float v[2], const float v_ref[2], f
normalize_v2_v2(v_unit, v);
angle = angle_signed_v2v2(v_unit, v_ref);
angle_delta = (roundf(angle / angle_snap) * angle_snap) - angle;
- rotate_m2(m2, angle_delta);
+ angle_to_mat2(m2, angle_delta);
mul_v2_m2v2(r, m2, v);
return angle + angle_delta;
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index e05ce727e22..1a2f9fdb62b 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -596,7 +596,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
BMVert *v_new;
BLI_assert(l_sep->v == v);
- v_new = bmesh_urmv_loop_region(bm, l_sep);
+ v_new = BM_face_loop_separate_multi_isolated(bm, l_sep);
BLI_assert(BM_vert_find_first_loop(v));
BM_vert_select_set(bm, v, false);
@@ -665,7 +665,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
BM_vert_select_set(bm, v, false);
- bmesh_vert_separate(bm, v, &vout, &vout_len, true);
+ bmesh_kernel_vert_separate(bm, v, &vout, &vout_len, true);
if (vout_len < 2) {
MEM_freeN(vout);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index a6de1b284b7..68bd8ff27b1 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -446,6 +446,9 @@ BMVert *EDBM_vert_find_nearest_ex(
unsigned int index;
BMVert *eve;
+ /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
+ ED_view3d_backbuf_validate(vc);
+
index = ED_view3d_backbuf_sample_rect(
vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test);
eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL;
@@ -630,7 +633,8 @@ BMEdge *EDBM_edge_find_nearest_ex(
float dist_test = 0.0f;
unsigned int index;
BMEdge *eed;
-
+
+ /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
ED_view3d_backbuf_validate(vc);
index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index c57b0215d46..c513c49aa8e 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -169,7 +169,7 @@ struct EdgeRingOpSubdProps {
};
-static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_default)
+static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_min, const int cuts_default)
{
/* Note, these values must match delete_mesh() event values */
static EnumPropertyItem prop_subd_edgering_types[] = {
@@ -181,7 +181,7 @@ static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_defa
PropertyRNA *prop;
- prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", 0, 64);
+ prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", cuts_min, 64);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_enum(ot->srna, "interpolation", prop_subd_edgering_types, SUBD_RING_INTERP_PATH,
@@ -248,7 +248,7 @@ void MESH_OT_subdivide_edgering(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- mesh_operator_edgering_props(ot, 10);
+ mesh_operator_edgering_props(ot, 1, 10);
}
@@ -306,7 +306,7 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
ED_view3d_init_mats_rv3d(obedit, ar->regiondata);
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE,
+ CTX_data_main(C), CTX_data_scene(C), 0,
ar, CTX_wm_view3d(C));
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
@@ -684,27 +684,38 @@ static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_
/* now we need to find the edge that isnt connected to this element */
BM_select_history_clear(bm);
+ /* Notes on hidden geometry:
+ * - un-hide the face since its possible hidden was copied when copying surrounding face attributes.
+ * - un-hide before adding to select history
+ * since we may extend into an existing, hidden vert/edge.
+ */
+
+ BM_elem_flag_disable(f, BM_ELEM_HIDDEN);
+ BM_face_select_set(bm, f, false);
+
if (ele_desel->head.htype == BM_VERT) {
BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel);
BLI_assert(f->len == 3);
- BM_face_select_set(bm, f, false);
BM_vert_select_set(bm, (BMVert *)ele_desel, false);
-
BM_edge_select_set(bm, l->next->e, true);
BM_select_history_store(bm, l->next->e);
}
else {
BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel);
BLI_assert(f->len == 4 || f->len == 3);
- BM_face_select_set(bm, f, false);
+
BM_edge_select_set(bm, (BMEdge *)ele_desel, false);
if (f->len == 4) {
- BM_edge_select_set(bm, l->next->next->e, true);
- BM_select_history_store(bm, l->next->next->e);
+ BMEdge *e_active = l->next->next->e;
+ BM_elem_flag_disable(e_active, BM_ELEM_HIDDEN);
+ BM_edge_select_set(bm, e_active, true);
+ BM_select_history_store(bm, e_active);
}
else {
- BM_vert_select_set(bm, l->next->next->v, true);
- BM_select_history_store(bm, l->next->next->v);
+ BMVert *v_active = l->next->next->v;
+ BM_elem_flag_disable(v_active, BM_ELEM_HIDDEN);
+ BM_vert_select_set(bm, v_active, true);
+ BM_select_history_store(bm, v_active);
}
}
}
@@ -758,6 +769,14 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
else
#endif
{
+ /* Newly created faces may include existing hidden edges,
+ * copying face data from surrounding, may have copied hidden face flag too.
+ *
+ * Important that faces use flushing since 'edges.out' wont include hidden edges that already existed.
+ */
+ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_HIDDEN, true);
+ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, false);
+
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
}
@@ -5216,8 +5235,10 @@ static int edbm_noise_exec(bContext *C, wmOperator *op)
else {
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- float tin, dum;
- externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false, false);
+ float tin = 0.0f, dum;
+ if (ma->mtex[ma->texact] != NULL) {
+ externtex(ma->mtex[ma->texact], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false, false);
+ }
eve->co[2] += fac * tin;
}
}
@@ -5426,7 +5447,7 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
RNA_def_float(ot->srna, "merge_factor", 0.5f, 0.0f, 1.0f, "Merge Factor", "", 0.0f, 1.0f);
RNA_def_int(ot->srna, "twist_offset", 0, -1000, 1000, "Twist", "Twist offset for closed loops", -1000, 1000);
- mesh_operator_edgering_props(ot, 0);
+ mesh_operator_edgering_props(ot, 0, 0);
}
static int edbm_wireframe_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index c9814d189a4..534ca22178e 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -369,7 +369,9 @@ struct UMArrayData {
UndoMesh *um;
const UndoMesh *um_ref; /* can be NULL */
};
-static void um_arraystore_compact_cb(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool),
+ void *taskdata,
+ int UNUSED(threadid))
{
struct UMArrayData *um_data = taskdata;
um_arraystore_compact_with_info(um_data->um, um_data->um_ref);
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 772bb1bd308..737c8ac665d 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -252,7 +252,7 @@ void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me)
{
/* could be ldata or pdata */
CustomData *pdata = GET_CD_DATA(me, pdata);
- const int layernum = CustomData_get_active_layer_index(pdata, CD_MTEXPOLY);
+ const int layernum = CustomData_get_active_layer(pdata, CD_MTEXPOLY);
ED_mesh_uv_loop_reset_ex(me, layernum);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
@@ -464,6 +464,20 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set)
return layernum;
}
+bool ED_mesh_color_ensure(struct Mesh *me, const char *name)
+{
+ BLI_assert(me->edit_btmesh == NULL);
+
+ if (!me->mloopcol && me->totloop) {
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name);
+ BKE_mesh_update_customdata_pointers(me, true);
+ }
+
+ DAG_id_tag_update(&me->id, 0);
+
+ return (me->mloopcol != NULL);
+}
+
bool ED_mesh_color_remove_index(Mesh *me, const int n)
{
CustomData *ldata = GET_CD_DATA(me, ldata);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index b26989113d4..c900373a59c 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -57,6 +57,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_material.h"
+#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
#include "BKE_multires.h"
@@ -75,26 +76,216 @@
/* join selected meshes into the active mesh, context sensitive
* return 0 if no join is made (error) and 1 if the join is done */
+static void join_mesh_single(
+ Main *bmain, Scene *scene,
+ Object *ob_dst, Object *ob_src, float imat[4][4],
+ MVert **mvert_pp, MEdge **medge_pp, MLoop **mloop_pp, MPoly **mpoly_pp,
+ CustomData *vdata, CustomData *edata, CustomData *ldata, CustomData *pdata,
+ int totvert, int totedge, int totloop, int totpoly,
+ Key *key, Key *nkey,
+ Material **matar, int *matmap, int totcol,
+ int *vertofs, int *edgeofs, int *loopofs, int *polyofs)
+{
+ int a, b;
+
+ Mesh *me = ob_src->data;
+ MVert *mvert = *mvert_pp;
+ MEdge *medge = *medge_pp;
+ MLoop *mloop = *mloop_pp;
+ MPoly *mpoly = *mpoly_pp;
+
+ if (me->totvert) {
+ /* merge customdata flag */
+ ((Mesh *)ob_dst->data)->cd_flag |= me->cd_flag;
+
+ /* standard data */
+ CustomData_merge(&me->vdata, vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
+ CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert);
+
+ /* vertex groups */
+ MDeformVert *dvert = CustomData_get(vdata, *vertofs, CD_MDEFORMVERT);
+ MDeformVert *dvert_src = CustomData_get(&me->vdata, 0, CD_MDEFORMVERT);
+
+ /* Remap to correct new vgroup indices, if needed. */
+ if (dvert_src) {
+ BLI_assert(dvert != NULL);
+
+ /* Build src to merged mapping of vgroup indices. */
+ bDeformGroup *dg_src;
+ int *vgroup_index_map = alloca(sizeof(*vgroup_index_map) * BLI_listbase_count(&ob_src->defbase));
+ bool is_vgroup_remap_needed = false;
+
+ for (dg_src = ob_src->defbase.first, b = 0; dg_src; dg_src = dg_src->next, b++) {
+ vgroup_index_map[b] = defgroup_name_index(ob_dst, dg_src->name);
+ is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[b] != b);
+ }
+
+ if (is_vgroup_remap_needed) {
+ for (a = 0; a < me->totvert; a++) {
+ for (b = 0; b < dvert[a].totweight; b++) {
+ dvert[a].dw[b].def_nr = vgroup_index_map[dvert_src[a].dw[b].def_nr];
+ }
+ }
+ }
+ }
+
+ /* if this is the object we're merging into, no need to do anything */
+ if (ob_src != ob_dst) {
+ float cmat[4][4];
+
+ /* watch this: switch matmul order really goes wrong */
+ mul_m4_m4m4(cmat, imat, ob_src->obmat);
+
+ /* transform vertex coordinates into new space */
+ for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, mvert++) {
+ mul_m4_v3(cmat, mvert->co);
+ }
+
+ /* for each shapekey in destination mesh:
+ * - if there's a matching one, copy it across (will need to transform vertices into new space...)
+ * - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space)
+ */
+ if (key) {
+ /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
+ for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ /* get pointer to where to write data for this mesh in shapekey's data array */
+ float (*cos)[3] = ((float (*)[3])kb->data) + *vertofs;
+
+ /* check if this mesh has such a shapekey */
+ KeyBlock *okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : NULL;
+ if (okb) {
+ /* copy this mesh's shapekey to the destination shapekey (need to transform first) */
+ float (*ocos)[3] = okb->data;
+ for (a = 0; a < me->totvert; a++, cos++, ocos++) {
+ copy_v3_v3(*cos, *ocos);
+ mul_m4_v3(cmat, *cos);
+ }
+ }
+ else {
+ /* copy this mesh's vertex coordinates to the destination shapekey */
+ for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) {
+ copy_v3_v3(*cos, mvert->co);
+ }
+ }
+ }
+ }
+ }
+ else {
+ /* for each shapekey in destination mesh:
+ * - if it was an 'original', copy the appropriate data from nkey
+ * - otherwise, copy across plain coordinates (no need to transform coordinates)
+ */
+ if (key) {
+ for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ /* get pointer to where to write data for this mesh in shapekey's data array */
+ float (*cos)[3] = ((float (*)[3])kb->data) + *vertofs;
+
+ /* check if this was one of the original shapekeys */
+ KeyBlock *okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : NULL;
+ if (okb) {
+ /* copy this mesh's shapekey to the destination shapekey */
+ float (*ocos)[3] = okb->data;
+ for (a = 0; a < me->totvert; a++, cos++, ocos++) {
+ copy_v3_v3(*cos, *ocos);
+ }
+ }
+ else {
+ /* copy base-coordinates to the destination shapekey */
+ for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) {
+ copy_v3_v3(*cos, mvert->co);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (me->totedge) {
+ CustomData_merge(&me->edata, edata, CD_MASK_MESH, CD_DEFAULT, totedge);
+ CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge);
+
+ for (a = 0; a < me->totedge; a++, medge++) {
+ medge->v1 += *vertofs;
+ medge->v2 += *vertofs;
+ }
+ }
+
+ if (me->totloop) {
+ if (ob_src != ob_dst) {
+ MultiresModifierData *mmd;
+
+ multiresModifier_prepare_join(scene, ob_src, ob_dst);
+
+ if ((mmd = get_multires_modifier(scene, ob_src, true))) {
+ ED_object_iter_other(bmain, ob_src, true,
+ ED_object_multires_update_totlevels_cb,
+ &mmd->totlvl);
+ }
+ }
+
+ CustomData_merge(&me->ldata, ldata, CD_MASK_MESH, CD_DEFAULT, totloop);
+ CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop);
+
+ for (a = 0; a < me->totloop; a++, mloop++) {
+ mloop->v += *vertofs;
+ mloop->e += *edgeofs;
+ }
+ }
+
+ if (me->totpoly) {
+ if (matmap) {
+ /* make mapping for materials */
+ for (a = 1; a <= ob_src->totcol; a++) {
+ Material *ma = give_current_material(ob_src, a);
+
+ for (b = 0; b < totcol; b++) {
+ if (ma == matar[b]) {
+ matmap[a - 1] = b;
+ break;
+ }
+ }
+ }
+ }
+
+ CustomData_merge(&me->pdata, pdata, CD_MASK_MESH, CD_DEFAULT, totpoly);
+ CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly);
+
+ for (a = 0; a < me->totpoly; a++, mpoly++) {
+ mpoly->loopstart += *loopofs;
+ mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0;
+ }
+ }
+
+ /* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */
+ *vertofs += me->totvert;
+ *mvert_pp += me->totvert;
+ *edgeofs += me->totedge;
+ *medge_pp += me->totedge;
+ *loopofs += me->totloop;
+ *mloop_pp += me->totloop;
+ *polyofs += me->totpoly;
+ *mpoly_pp += me->totpoly;
+}
+
int join_mesh_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- Material **matar, *ma;
+ Material **matar = NULL, *ma;
Mesh *me;
- MVert *mvert, *mv;
+ MVert *mvert = NULL;
MEdge *medge = NULL;
MPoly *mpoly = NULL;
MLoop *mloop = NULL;
Key *key, *nkey = NULL;
- KeyBlock *kb, *okb, *kbn;
- float imat[4][4], cmat[4][4], *fp1, *fp2;
+ KeyBlock *kb, *kbn;
+ float imat[4][4];
int a, b, totcol, totmat = 0, totedge = 0, totvert = 0;
int totloop = 0, totpoly = 0, vertofs, *matmap = NULL;
- int i, j, index, haskey = 0, edgeofs, loopofs, polyofs;
+ int i, haskey = 0, edgeofs, loopofs, polyofs;
bool ok = false;
bDeformGroup *dg, *odg;
- MDeformVert *dvert;
CustomData vdata, edata, fdata, ldata, pdata;
if (scene->obedit) {
@@ -154,8 +345,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
BKE_mesh_tessface_clear(me);
/* new material indices and material array */
- matar = MEM_callocN(sizeof(void *) * totmat, "join_mesh matar");
- if (totmat) matmap = MEM_callocN(sizeof(int) * totmat, "join_mesh matmap");
+ if (totmat) {
+ matar = MEM_callocN(sizeof(*matar) * totmat, "join_mesh matar");
+ matmap = MEM_callocN(sizeof(*matmap) * totmat, "join_mesh matmap");
+ }
totcol = ob->totcol;
/* obact materials in new main array, is nicer start! */
@@ -214,7 +407,9 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ma = give_current_material(base->object, a);
for (b = 0; b < totcol; b++) {
- if (ma == matar[b]) break;
+ if (ma == matar[b]) {
+ break;
+ }
}
if (b == totcol) {
matar[b] = ma;
@@ -223,8 +418,9 @@ int join_mesh_exec(bContext *C, wmOperator *op)
}
totcol++;
}
- if (totcol >= MAXMAT)
+ if (totcol >= MAXMAT) {
break;
+ }
}
}
@@ -252,15 +448,6 @@ int join_mesh_exec(bContext *C, wmOperator *op)
/* adjust settings to fit (allocate a new data-array) */
kbn->data = MEM_callocN(sizeof(float) * 3 * totvert, "joined_shapekey");
kbn->totelem = totvert;
-
- /* XXX 2.5 Animato */
-#if 0
- /* also, copy corresponding ipo-curve to ipo-block if applicable */
- if (me->key->ipo && key->ipo) {
- /* FIXME... this is a luxury item! */
- puts("FIXME: ignoring IPO's when joining shapekeys on Meshes for now...");
- }
-#endif
}
kb_map[i] = kbn;
@@ -301,187 +488,41 @@ int join_mesh_exec(bContext *C, wmOperator *op)
/* inverse transform for all selected meshes in this object */
invert_m4_m4(imat, ob->obmat);
-
+
+ /* Add back active mesh first. This allows to keep things similar as they were, as much as possible (i.e. data from
+ * active mesh will remain first ones in new result of the merge, in same order for CD layers, etc. See also T50084.
+ */
+ join_mesh_single(
+ bmain, scene,
+ ob, ob, imat,
+ &mvert, &medge, &mloop, &mpoly,
+ &vdata, &edata, &ldata, &pdata,
+ totvert, totedge, totloop, totpoly,
+ key, nkey,
+ matar, matmap, totcol,
+ &vertofs, &edgeofs, &loopofs, &polyofs);
+
CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
{
+ if (base->object == ob) {
+ continue;
+ }
/* only join if this is a mesh */
if (base->object->type == OB_MESH) {
- me = base->object->data;
-
- if (me->totvert) {
-
- /* merge customdata flag */
- ((Mesh *)ob->data)->cd_flag |= me->cd_flag;
-
- /* standard data */
- CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
- CustomData_copy_data_named(&me->vdata, &vdata, 0, vertofs, me->totvert);
-
- /* vertex groups */
- dvert = CustomData_get(&vdata, vertofs, CD_MDEFORMVERT);
-
- /* NB: vertex groups here are new version */
- if (dvert) {
- for (i = 0; i < me->totvert; i++) {
- for (j = 0; j < dvert[i].totweight; j++) {
- /* Find the old vertex group */
- odg = BLI_findlink(&base->object->defbase, dvert[i].dw[j].def_nr);
- if (odg) {
- /* Search for a match in the new object, and set new index */
- for (dg = ob->defbase.first, index = 0; dg; dg = dg->next, index++) {
- if (STREQ(dg->name, odg->name)) {
- dvert[i].dw[j].def_nr = index;
- break;
- }
- }
- }
- }
- }
- }
-
- /* if this is the object we're merging into, no need to do anything */
- if (base->object != ob) {
- /* watch this: switch matmul order really goes wrong */
- mul_m4_m4m4(cmat, imat, base->object->obmat);
-
- /* transform vertex coordinates into new space */
- for (a = 0, mv = mvert; a < me->totvert; a++, mv++) {
- mul_m4_v3(cmat, mv->co);
- }
-
- /* for each shapekey in destination mesh:
- * - if there's a matching one, copy it across (will need to transform vertices into new space...)
- * - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space)
- */
- if (key) {
- /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
- for (kb = key->block.first; kb; kb = kb->next) {
- /* get pointer to where to write data for this mesh in shapekey's data array */
- fp1 = ((float *)kb->data) + (vertofs * 3);
-
- /* check if this mesh has such a shapekey */
- okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : NULL;
-
- if (okb) {
- /* copy this mesh's shapekey to the destination shapekey (need to transform first) */
- fp2 = ((float *)(okb->data));
- for (a = 0; a < me->totvert; a++, fp1 += 3, fp2 += 3) {
- copy_v3_v3(fp1, fp2);
- mul_m4_v3(cmat, fp1);
- }
- }
- else {
- /* copy this mesh's vertex coordinates to the destination shapekey */
- mv = mvert;
- for (a = 0; a < me->totvert; a++, fp1 += 3, mv++) {
- copy_v3_v3(fp1, mv->co);
- }
- }
- }
- }
- }
- else {
- /* for each shapekey in destination mesh:
- * - if it was an 'original', copy the appropriate data from nkey
- * - otherwise, copy across plain coordinates (no need to transform coordinates)
- */
- if (key) {
- for (kb = key->block.first; kb; kb = kb->next) {
- /* get pointer to where to write data for this mesh in shapekey's data array */
- fp1 = ((float *)kb->data) + (vertofs * 3);
-
- /* check if this was one of the original shapekeys */
- okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : NULL;
- if (okb) {
- /* copy this mesh's shapekey to the destination shapekey */
- fp2 = ((float *)(okb->data));
- for (a = 0; a < me->totvert; a++, fp1 += 3, fp2 += 3) {
- copy_v3_v3(fp1, fp2);
- }
- }
- else {
- /* copy base-coordinates to the destination shapekey */
- mv = mvert;
- for (a = 0; a < me->totvert; a++, fp1 += 3, mv++) {
- copy_v3_v3(fp1, mv->co);
- }
- }
- }
- }
- }
-
- /* advance mvert pointer to end of base mesh's data */
- mvert += me->totvert;
- }
-
- if (me->totedge) {
- CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
- CustomData_copy_data_named(&me->edata, &edata, 0, edgeofs, me->totedge);
-
- for (a = 0; a < me->totedge; a++, medge++) {
- medge->v1 += vertofs;
- medge->v2 += vertofs;
- }
- }
-
- if (me->totloop) {
- if (base->object != ob) {
- MultiresModifierData *mmd;
-
- multiresModifier_prepare_join(scene, base->object, ob);
+ join_mesh_single(
+ bmain, scene,
+ ob, base->object, imat,
+ &mvert, &medge, &mloop, &mpoly,
+ &vdata, &edata, &ldata, &pdata,
+ totvert, totedge, totloop, totpoly,
+ key, nkey,
+ matar, matmap, totcol,
+ &vertofs, &edgeofs, &loopofs, &polyofs);
- if ((mmd = get_multires_modifier(scene, base->object, true))) {
- ED_object_iter_other(bmain, base->object, true,
- ED_object_multires_update_totlevels_cb,
- &mmd->totlvl);
- }
- }
-
- CustomData_merge(&me->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop);
- CustomData_copy_data_named(&me->ldata, &ldata, 0, loopofs, me->totloop);
-
- for (a = 0; a < me->totloop; a++, mloop++) {
- mloop->v += vertofs;
- mloop->e += edgeofs;
- }
- }
-
- if (me->totpoly) {
- if (totmat) {
- /* make mapping for materials */
- for (a = 1; a <= base->object->totcol; a++) {
- ma = give_current_material(base->object, a);
-
- for (b = 0; b < totcol; b++) {
- if (ma == matar[b]) {
- matmap[a - 1] = b;
- break;
- }
- }
- }
- }
-
- CustomData_merge(&me->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly);
- CustomData_copy_data_named(&me->pdata, &pdata, 0, polyofs, me->totpoly);
-
- for (a = 0; a < me->totpoly; a++, mpoly++) {
- mpoly->loopstart += loopofs;
- mpoly->mat_nr = matmap ? matmap[(int)mpoly->mat_nr] : 0;
- }
-
- polyofs += me->totpoly;
- }
-
- /* these are used for relinking (cannot be set earlier,
- * or else reattaching goes wrong)
- */
- vertofs += me->totvert;
- edgeofs += me->totedge;
- loopofs += me->totloop;
-
/* free base, now that data is merged */
- if (base->object != ob)
+ if (base->object != ob) {
ED_base_object_free_and_unlink(bmain, scene, base);
+ }
}
}
CTX_DATA_END;
@@ -529,34 +570,20 @@ int join_mesh_exec(bContext *C, wmOperator *op)
if (totcol) {
me->mat = matar;
- ob->mat = MEM_callocN(sizeof(void *) * totcol, "join obmatar");
- ob->matbits = MEM_callocN(sizeof(char) * totcol, "join obmatbits");
+ ob->mat = MEM_callocN(sizeof(*ob->mat) * totcol, "join obmatar");
+ ob->matbits = MEM_callocN(sizeof(*ob->matbits) * totcol, "join obmatbits");
+ MEM_freeN(matmap);
}
- else
- MEM_freeN(matar);
-
+
ob->totcol = me->totcol = totcol;
- if (matmap) MEM_freeN(matmap);
-
/* other mesh users */
test_all_objects_materials(bmain, (ID *)me);
/* free temp copy of destination shapekeys (if applicable) */
if (nkey) {
- /* XXX 2.5 Animato */
-#if 0
- /* free it's ipo too - both are not actually freed from memory yet as ID-blocks */
- if (nkey->ipo) {
- BKE_ipo_free(nkey->ipo);
- BLI_remlink(&bmain->ipo, nkey->ipo);
- MEM_freeN(nkey->ipo);
- }
-#endif
-
- BKE_key_free(nkey);
- BLI_remlink(&bmain->key, nkey);
- MEM_freeN(nkey);
+ /* We can assume nobody is using that ID currently. */
+ BKE_libblock_free_ex(bmain, nkey, false, false);
}
/* ensure newly inserted keys are time sorted */
@@ -564,7 +591,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
BKE_key_sort(key);
}
- DAG_relations_tag_update(bmain); // removed objects, need to rebuild dag
+ /* Due to dependnecy cycle some other object might access old derived data. */
+ BKE_object_free_derived_caches(ob);
+
+ DAG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index ed5bf4a92b4..bc42717b69f 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -592,12 +592,9 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
view3d_set_viewcontext(C, &vc);
- rect.xmin = mval[0] - 12;
- rect.xmax = mval[0] + 12;
- rect.ymin = mval[1] - 12;
- rect.ymax = mval[1] + 12;
+ BLI_rcti_init_pt_radius(&rect, mval, 12);
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
/* does startelem exist? */
ml = mb->editelems->first;
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 6647102acad..a0bb5ce3fc9 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -64,6 +64,7 @@
#include "BKE_armature.h"
#include "BKE_camera.h"
#include "BKE_context.h"
+#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
@@ -75,6 +76,7 @@
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -977,7 +979,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
group = (Group *)BKE_libblock_find_name(ID_GR, name);
if (0 == RNA_struct_property_is_set(op->ptr, "location")) {
- wmEvent *event = CTX_wm_window(C)->eventstate;
+ const wmEvent *event = CTX_wm_window(C)->eventstate;
ARegion *ar = CTX_wm_region(C);
const int mval[2] = {event->x - ar->winrct.xmin,
event->y - ar->winrct.ymin};
@@ -1110,7 +1112,9 @@ 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)
{
- if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
+ if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
+ ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0)
+ {
/* We cannot delete indirectly used object... */
printf("WARNING, undeletable object '%s', should have been catched before reaching this function!",
base->object->id.name + 2);
@@ -1144,13 +1148,27 @@ static int object_delete_exec(bContext *C, wmOperator *op)
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) {
+ else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) {
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;
}
+
+ /* This is sort of a quick hack to address T51243 - Proper thing to do here would be to nuke most of all this
+ * custom scene/object/base handling, and use generic lib remap/query for that.
+ * But this is for later (aka 2.8, once layers & co are settled and working).
+ */
+ if (use_global && base->object->id.lib == NULL) {
+ /* We want to nuke the object, let's nuke it the easy way (not for linked data though)... */
+ BKE_libblock_delete(bmain, &base->object->id);
+ changed = true;
+ continue;
+ }
+
/* remove from Grease Pencil parent */
+ /* XXX This is likely not correct? Will also remove parent from grease pencil from other scenes,
+ * even when use_global is false... */
for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
if (gpl->parent != NULL) {
@@ -1178,7 +1196,7 @@ static int object_delete_exec(bContext *C, wmOperator *op)
if (scene_iter != scene && !ID_IS_LINKED_DATABLOCK(scene_iter)) {
base_other = BKE_scene_base_find(scene_iter, base->object);
if (base_other) {
- if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) {
+ if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) {
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);
@@ -1241,7 +1259,7 @@ static void copy_object_set_idnew(bContext *C)
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
- BKE_libblock_relink(&ob->id);
+ BKE_libblock_relink_to_newid(&ob->id);
}
CTX_DATA_END;
@@ -1326,84 +1344,87 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
const bool use_hierarchy)
{
Main *bmain = CTX_data_main(C);
- ListBase *lb;
+ ListBase *lb_duplis;
DupliObject *dob;
- GHash *dupli_gh = NULL, *parent_gh = NULL;
- Object *object;
+ GHash *dupli_gh, *parent_gh = NULL;
- if (!(base->object->transflag & OB_DUPLI))
+ if (!(base->object->transflag & OB_DUPLI)) {
return;
+ }
- lb = object_duplilist(bmain->eval_ctx, scene, base->object);
+ lb_duplis = object_duplilist(bmain->eval_ctx, scene, base->object);
- if (use_hierarchy || use_base_parent) {
- dupli_gh = BLI_ghash_ptr_new(__func__);
- if (use_hierarchy) {
- if (base->object->transflag & OB_DUPLIGROUP) {
- parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__);
- }
- else {
- parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__);
- }
+ dupli_gh = BLI_ghash_ptr_new(__func__);
+ if (use_hierarchy) {
+ if (base->object->transflag & OB_DUPLIGROUP) {
+ parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__);
+ }
+ else {
+ parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__);
}
}
- for (dob = lb->first; dob; dob = dob->next) {
- Base *basen;
- Object *ob = BKE_object_copy(bmain, dob->ob);
+ for (dob = lb_duplis->first; dob; dob = dob->next) {
+ Object *ob_src = dob->ob;
+ Object *ob_dst = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, ob_src));
+ Base *base_dst;
/* font duplis can have a totcol without material, we get them from parent
* should be implemented better...
*/
- if (ob->mat == NULL) ob->totcol = 0;
+ if (ob_dst->mat == NULL) {
+ ob_dst->totcol = 0;
+ }
- basen = MEM_dupallocN(base);
- basen->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP);
- ob->flag = basen->flag;
- basen->lay = base->lay;
- BLI_addhead(&scene->base, basen); /* addhead: othwise eternal loop */
- basen->object = ob;
+ base_dst = MEM_dupallocN(base);
+ base_dst->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP);
+ ob_dst->flag = base_dst->flag;
+ base_dst->lay = base->lay;
+ BLI_addhead(&scene->base, base_dst); /* addhead: othwise eternal loop */
+ base_dst->object = ob_dst;
/* make sure apply works */
- BKE_animdata_free(&ob->id, true);
- ob->adt = NULL;
+ BKE_animdata_free(&ob_dst->id, true);
+ ob_dst->adt = NULL;
/* Proxies are not to be copied. */
- ob->proxy_from = NULL;
- ob->proxy_group = NULL;
- ob->proxy = NULL;
+ ob_dst->proxy_from = NULL;
+ ob_dst->proxy_group = NULL;
+ ob_dst->proxy = NULL;
- ob->parent = NULL;
- BLI_listbase_clear(&ob->constraints);
- ob->curve_cache = NULL;
- ob->transflag &= ~OB_DUPLI;
- ob->lay = base->lay;
+ ob_dst->parent = NULL;
+ BKE_constraints_free(&ob_dst->constraints);
+ ob_dst->curve_cache = NULL;
+ ob_dst->transflag &= ~OB_DUPLI;
+ ob_dst->lay = base->lay;
- copy_m4_m4(ob->obmat, dob->mat);
- BKE_object_apply_mat4(ob, ob->obmat, false, false);
+ copy_m4_m4(ob_dst->obmat, dob->mat);
+ BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false);
- if (dupli_gh) {
- BLI_ghash_insert(dupli_gh, dob, ob);
- }
+ BLI_ghash_insert(dupli_gh, dob, ob_dst);
if (parent_gh) {
void **val;
/* Due to nature of hash/comparison of this ghash, a lot of duplis may be considered as 'the same',
* this avoids trying to insert same key several time and raise asserts in debug builds... */
if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) {
- *val = ob;
+ *val = ob_dst;
}
}
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
- if (use_hierarchy) {
- for (dob = lb->first; dob; dob = dob->next) {
+ for (dob = lb_duplis->first; dob; dob = dob->next) {
+ Object *ob_src = dob->ob;
+ Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob);
+
+ /* Remap new object to itself, and clear again newid pointer of orig object. */
+ BKE_libblock_relink_to_newid(&ob_dst->id);
+ set_sca_new_poins_ob(ob_dst);
+
+ DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+
+ if (use_hierarchy) {
/* original parents */
- Object *ob_src = dob->ob;
Object *ob_src_par = ob_src->parent;
-
- Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob);
Object *ob_dst_par = NULL;
/* find parent that was also made real */
@@ -1414,8 +1435,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
dob_key.ob = ob_src_par;
if (base->object->transflag & OB_DUPLIGROUP) {
memcpy(&dob_key.persistent_id[1],
- &dob->persistent_id[1],
- sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1));
+ &dob->persistent_id[1],
+ sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1));
}
else {
dob_key.persistent_id[0] = dob->persistent_id[0];
@@ -1439,54 +1460,42 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
ob_dst->parent = base->object;
ob_dst->partype = PAROBJECT;
}
-
- if (ob_dst->parent) {
- invert_m4_m4(ob_dst->parentinv, dob->mat);
-
- /* note, this may be the parent of other objects, but it should
- * still work out ok */
- BKE_object_apply_mat4(ob_dst, dob->mat, false, true);
-
- /* to set ob_dst->orig and in case theres any other discrepicies */
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB);
- }
}
- }
- else if (use_base_parent) {
- /* since we are ignoring the internal hierarchy - parent all to the
- * base object */
- for (dob = lb->first; dob; dob = dob->next) {
- /* original parents */
- Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob);
-
+ else if (use_base_parent) {
+ /* since we are ignoring the internal hierarchy - parent all to the
+ * base object */
ob_dst->parent = base->object;
ob_dst->partype = PAROBJECT;
+ }
- /* similer to the code above, see comments */
- invert_m4_m4(ob_dst->parentinv, dob->mat);
+ if (ob_dst->parent) {
+ /* note, this may be the parent of other objects, but it should
+ * still work out ok */
BKE_object_apply_mat4(ob_dst, dob->mat, false, true);
+
+ /* to set ob_dst->orig and in case theres any other discrepicies */
DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB);
}
}
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) {
- object->proxy = NULL;
- object->proxy_from = NULL;
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->proxy_group == base->object) {
+ ob->proxy = NULL;
+ ob->proxy_from = NULL;
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
}
}
- if (dupli_gh)
- BLI_ghash_free(dupli_gh, NULL, NULL);
- if (parent_gh)
+ BLI_ghash_free(dupli_gh, NULL, NULL);
+ if (parent_gh) {
BLI_ghash_free(parent_gh, NULL, NULL);
+ }
- copy_object_set_idnew(C);
+ free_object_duplilist(lb_duplis);
- free_object_duplilist(lb);
+ BKE_main_id_clear_newpoins(bmain);
base->object->transflag &= ~OB_DUPLI;
}
@@ -1619,7 +1628,7 @@ static int convert_exec(bContext *C, wmOperator *op)
MetaBall *mb;
Mesh *me;
const short target = RNA_enum_get(op->ptr, "target");
- const bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
+ bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
int a, mballConverted = 0;
/* don't forget multiple users! */
@@ -1649,8 +1658,38 @@ static int convert_exec(bContext *C, wmOperator *op)
}
}
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ ListBase selected_editable_bases = CTX_data_collection_get(C, "selected_editable_bases");
+
+ /* Ensure we get all meshes calculated with a sufficient data-mask,
+ * needed since re-evaluating single modifiers causes bugs if they depend
+ * on other objects data masks too, see: T50950. */
{
+ for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
+ Base *base = link->ptr.data;
+ ob = base->object;
+
+ /* The way object type conversion works currently (enforcing conversion of *all* objetcs using converted
+ * obdata, even some un-selected/hidden/inother scene ones, sounds totally bad to me.
+ * However, changing this is more design than bugfix, not to mention convoluted code below,
+ * so that will be for later.
+ * But at the very least, do not do that with linked IDs! */
+ if ((ID_IS_LINKED_DATABLOCK(ob) || (ob->data && ID_IS_LINKED_DATABLOCK(ob->data))) && !keep_original) {
+ keep_original = true;
+ BKE_reportf(op->reports, RPT_INFO,
+ "Converting some linked object/object data, enforcing 'Keep Original' option to True");
+ }
+
+ DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
+ }
+
+ uint64_t customdata_mask_prev = scene->customdata_mask;
+ scene->customdata_mask |= CD_MASK_MESH;
+ BKE_scene_update_tagged(bmain->eval_ctx, bmain, scene);
+ scene->customdata_mask = customdata_mask_prev;
+ }
+
+ for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
+ Base *base = link->ptr.data;
ob = base->object;
if (ob->flag & OB_DONE || !IS_TAGGED(ob->data)) {
@@ -1693,7 +1732,7 @@ static int convert_exec(bContext *C, wmOperator *op)
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 */
+ else if (ob->type == OB_MESH) {
ob->flag |= OB_DONE;
if (keep_original) {
@@ -1717,7 +1756,6 @@ static int convert_exec(bContext *C, wmOperator *op)
* cases this doesnt give correct results (when MDEF is used for eg)
*/
dm = mesh_get_derived_final(scene, newob, CD_MASK_MESH);
- // dm = mesh_create_derived_no_deform(ob1, NULL); /* this was called original (instead of get_derived). man o man why! (ton) */
DM_to_mesh(dm, newob->data, newob, CD_MASK_MESH, true);
@@ -1882,7 +1920,7 @@ static int convert_exec(bContext *C, wmOperator *op)
((ID *)ob->data)->tag &= ~LIB_TAG_DOIT; /* flag not to convert this datablock again */
}
}
- CTX_DATA_END;
+ BLI_freelistN(&selected_editable_bases);
if (!keep_original) {
if (mballConverted) {
@@ -1960,8 +1998,12 @@ void OBJECT_OT_convert(wmOperatorType *ot)
/* used below, assumes id.new is correct */
/* leaves selection of base/object unaltered */
+/* Does set ID->newid pointers. */
static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base, int dupflag)
{
+#define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; }
+#define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; }
+
Base *basen = NULL;
Material ***matarar;
Object *ob, *obn;
@@ -1973,7 +2015,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
; /* nothing? */
}
else {
- obn = BKE_object_copy(bmain, ob);
+ obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
basen = MEM_mallocN(sizeof(Base), "duplibase");
@@ -1995,20 +2037,21 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
/* duplicates using userflags */
if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(&obn->id);
+ BKE_animdata_copy_id_action(&obn->id, true);
}
if (dupflag & USER_DUP_MAT) {
for (a = 0; a < obn->totcol; a++) {
id = (ID *)obn->mat[a];
if (id) {
- ID_NEW_US(obn->mat[a])
- else
- obn->mat[a] = BKE_material_copy(bmain, obn->mat[a]);
+ ID_NEW_REMAP_US(obn->mat[a])
+ else {
+ obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a]));
+ }
id_us_min(id);
if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(&obn->mat[a]->id);
+ BKE_animdata_copy_id_action(&obn->mat[a]->id, true);
}
}
}
@@ -2018,12 +2061,13 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
for (psys = obn->particlesystem.first; psys; psys = psys->next) {
id = (ID *) psys->part;
if (id) {
- ID_NEW_US(psys->part)
- else
- psys->part = BKE_particlesettings_copy(bmain, psys->part);
+ ID_NEW_REMAP_US(psys->part)
+ else {
+ psys->part = ID_NEW_SET(psys->part, BKE_particlesettings_copy(bmain, psys->part));
+ }
if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(&psys->part->id);
+ BKE_animdata_copy_id_action(&psys->part->id, true);
}
id_us_min(id);
@@ -2037,9 +2081,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
switch (obn->type) {
case OB_MESH:
if (dupflag & USER_DUP_MESH) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_mesh_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_mesh_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2047,9 +2091,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_CURVE:
if (dupflag & USER_DUP_CURVE) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_curve_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2057,9 +2101,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_SURF:
if (dupflag & USER_DUP_SURF) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_curve_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2067,9 +2111,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_FONT:
if (dupflag & USER_DUP_FONT) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_curve_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2077,9 +2121,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_MBALL:
if (dupflag & USER_DUP_MBALL) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_mball_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_mball_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2087,9 +2131,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_LAMP:
if (dupflag & USER_DUP_LAMP) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_lamp_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_lamp_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2100,9 +2144,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (obn->pose)
BKE_pose_tag_recalc(bmain, obn->pose);
if (dupflag & USER_DUP_ARM) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_armature_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data));
BKE_pose_rebuild(obn, obn->data);
didit = 1;
}
@@ -2111,9 +2155,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_LATTICE:
if (dupflag != 0) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_lattice_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_lattice_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2121,9 +2165,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_CAMERA:
if (dupflag != 0) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_camera_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_camera_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2131,9 +2175,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_SPEAKER:
if (dupflag != 0) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_speaker_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_speaker_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2145,15 +2189,23 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (didit) {
Key *key = BKE_key_from_object(obn);
+ Key *oldkey = BKE_key_from_object(ob);
+ if (oldkey != NULL) {
+ ID_NEW_SET(oldkey, key);
+ }
+
if (dupflag & USER_DUP_ACT) {
bActuator *act;
- BKE_animdata_copy_id_action((ID *)obn->data);
+ BKE_animdata_copy_id_action((ID *)obn->data, true);
if (key) {
- BKE_animdata_copy_id_action((ID *)key);
+ BKE_animdata_copy_id_action((ID *)key, true);
}
/* Update the duplicated action in the action actuators */
+ /* XXX TODO this code is all wrong! actact->act is user-refcounted (see readfile.c),
+ * and what about other ID pointers of other BGE logic bricks,
+ * and since this is object-level, why is it only ran if obdata was duplicated??? -mont29 */
for (act = obn->actuators.first; act; act = act->next) {
if (act->type == ACT_ACTION) {
bActionActuator *actact = (bActionActuator *) act->data;
@@ -2170,9 +2222,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
for (a = 0; a < obn->totcol; a++) {
id = (ID *)(*matarar)[a];
if (id) {
- ID_NEW_US((*matarar)[a])
- else
- (*matarar)[a] = BKE_material_copy(bmain, (*matarar)[a]);
+ ID_NEW_REMAP_US((*matarar)[a])
+ else {
+ (*matarar)[a] = ID_NEW_SET((*matarar)[a], BKE_material_copy(bmain, (*matarar)[a]));
+ }
id_us_min(id);
}
}
@@ -2181,6 +2234,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
}
}
return basen;
+
+#undef ID_NEW_REMAP_US
+#undef ID_NEW_REMAP_US2
}
/* single object duplicate, if dupflag==0, fully linked, else it uses the flags given */
@@ -2193,8 +2249,7 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag
Base *basen;
Object *ob;
- BKE_main_id_clear_newpoins(bmain);
- clear_sca_new_poins(); /* sensor/contr/act */
+ clear_sca_new_poins(); /* BGE logic */
basen = object_add_duplicate_internal(bmain, scene, base, dupflag);
if (basen == NULL) {
@@ -2204,7 +2259,7 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag
ob = basen->object;
/* link own references to the newly duplicated data [#26816] */
- BKE_libblock_relink(&ob->id);
+ BKE_libblock_relink_to_newid(&ob->id);
set_sca_new_poins_ob(ob);
/* DAG_relations_tag_update(bmain); */ /* caller must do */
@@ -2213,6 +2268,8 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag
ED_render_id_flush_update(bmain, ob->data);
}
+ BKE_main_id_clear_newpoins(bmain);
+
return basen;
}
@@ -2224,8 +2281,7 @@ static int duplicate_exec(bContext *C, wmOperator *op)
const bool linked = RNA_boolean_get(op->ptr, "linked");
int dupflag = (linked) ? 0 : U.dupflag;
- BKE_main_id_clear_newpoins(bmain);
- clear_sca_new_poins(); /* sensor/contr/act */
+ clear_sca_new_poins(); /* BGE logic */
CTX_DATA_BEGIN (C, Base *, base, selected_bases)
{
@@ -2251,6 +2307,8 @@ static int duplicate_exec(bContext *C, wmOperator *op)
copy_object_set_idnew(C);
+ BKE_main_id_clear_newpoins(bmain);
+
DAG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -2309,8 +2367,7 @@ static int add_named_exec(bContext *C, wmOperator *op)
base->flag = ob->flag;
/* prepare dupli */
- BKE_main_id_clear_newpoins(bmain);
- clear_sca_new_poins(); /* sensor/contr/act */
+ clear_sca_new_poins(); /* BGE logic */
basen = object_add_duplicate_internal(bmain, scene, base, dupflag);
@@ -2336,6 +2393,8 @@ static int add_named_exec(bContext *C, wmOperator *op)
copy_object_set_idnew(C);
+ BKE_main_id_clear_newpoins(bmain);
+
DAG_relations_tag_update(bmain);
MEM_freeN(base);
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index fd95d6129ad..122330f7ede 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -51,6 +51,7 @@
#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_modifier.h"
@@ -352,12 +353,17 @@ static bool is_noncolor_pass(ScenePassType pass_type)
}
/* if all is good tag image and return true */
-static bool bake_object_check(Object *ob, ReportList *reports)
+static bool bake_object_check(Scene *scene, Object *ob, ReportList *reports)
{
Image *image;
void *lock;
int i;
+ if ((ob->lay & scene->lay) == 0) {
+ BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not on a scene layer", ob->id.name + 2);
+ return false;
+ }
+
if (ob->type != OB_MESH) {
BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh", ob->id.name + 2);
return false;
@@ -406,22 +412,18 @@ static bool bake_object_check(Object *ob, ReportList *reports)
}
}
else {
- if (ob->mat[i]) {
- BKE_reportf(reports, RPT_ERROR,
+ Material *mat = give_current_material(ob, i);
+ if (mat != NULL) {
+ BKE_reportf(reports, RPT_INFO,
"No active image found in material \"%s\" (%d) for object \"%s\"",
- ob->mat[i]->id.name + 2, i, ob->id.name + 2);
- }
- else if (((Mesh *) ob->data)->mat[i]) {
- BKE_reportf(reports, RPT_ERROR,
- "No active image found in material \"%s\" (%d) for object \"%s\"",
- ((Mesh *) ob->data)->mat[i]->id.name + 2, i, ob->id.name + 2);
+ mat->id.name + 2, i, ob->id.name + 2);
}
else {
- BKE_reportf(reports, RPT_ERROR,
- "No active image found in material (%d) for object \"%s\"",
+ BKE_reportf(reports, RPT_INFO,
+ "No active image found in material slot (%d) for object \"%s\"",
i, ob->id.name + 2);
}
- return false;
+ continue;
}
image->id.tag |= LIB_TAG_DOIT;
@@ -491,7 +493,7 @@ static bool bake_pass_filter_check(ScenePassType pass_type, const int pass_filte
}
/* before even getting in the bake function we check for some basic errors */
-static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objects,
+static bool bake_objects_check(Main *bmain, Scene *scene, Object *ob, ListBase *selected_objects,
ReportList *reports, const bool is_selected_to_active)
{
CollectionPointerLink *link;
@@ -502,7 +504,7 @@ static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objec
if (is_selected_to_active) {
int tot_objects = 0;
- if (!bake_object_check(ob, reports))
+ if (!bake_object_check(scene, ob, reports))
return false;
for (link = selected_objects->first; link; link = link->next) {
@@ -530,7 +532,7 @@ static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objec
}
for (link = selected_objects->first; link; link = link->next) {
- if (!bake_object_check(link->ptr.data, reports))
+ if (!bake_object_check(scene, link->ptr.data, reports))
return false;
}
}
@@ -561,7 +563,11 @@ static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images)
Image *image;
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
- if ((image->id.tag & LIB_TAG_DOIT)) {
+ /* Some materials have no image, we just ignore those cases. */
+ if (image == NULL) {
+ bake_images->lookup[i] = -1;
+ }
+ else if (image->id.tag & LIB_TAG_DOIT) {
for (j = 0; j < i; j++) {
if (bake_images->data[j].image == image) {
bake_images->lookup[i] = j;
@@ -619,7 +625,9 @@ static Mesh *bake_mesh_new_from_object(Main *bmain, Scene *scene, Object *ob)
ED_object_editmode_load(ob);
Mesh *me = BKE_mesh_new_from_object(bmain, scene, ob, 1, 2, 0, 0);
- BKE_mesh_split_faces(me);
+ if (me->flag & ME_AUTOSMOOTH) {
+ BKE_mesh_split_faces(me, true);
+ }
return me;
}
@@ -1023,7 +1031,7 @@ cage_cleanup:
}
else {
/* if everything else fails, use the material index */
- char tmp[4];
+ char tmp[5];
sprintf(tmp, "%d", i % 1000);
BLI_path_suffix(name, FILE_MAX, tmp, "_");
}
@@ -1153,7 +1161,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->result = OPERATOR_CANCELLED;
- bkr->render = RE_NewRender(bkr->scene->id.name);
+ bkr->render = RE_NewSceneRender(bkr->scene);
/* XXX hack to force saving to always be internal. Whether (and how) to support
* external saving will be addressed later */
@@ -1167,6 +1175,9 @@ static int bake_exec(bContext *C, wmOperator *op)
BakeAPIRender bkr = {NULL};
Scene *scene = CTX_data_scene(C);
+ G.is_break = false;
+ G.is_rendering = true;
+
bake_set_props(op, scene);
bake_init_api_data(op, C, &bkr);
@@ -1179,7 +1190,7 @@ static int bake_exec(bContext *C, wmOperator *op)
goto finally;
}
- if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) {
+ if (!bake_objects_check(bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) {
goto finally;
}
@@ -1218,6 +1229,7 @@ static int bake_exec(bContext *C, wmOperator *op)
finally:
+ G.is_rendering = false;
BLI_freelistN(&bkr.selected_objects);
return result;
}
@@ -1237,7 +1249,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
return;
}
- if (!bake_objects_check(bkr->main, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) {
+ if (!bake_objects_check(bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) {
bkr->result = OPERATOR_CANCELLED;
return;
}
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 111afcdc7a7..4a96a2e2200 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -41,6 +41,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -772,9 +773,9 @@ static void copymenu_logicbricks(Scene *scene, View3D *v3d, Object *ob)
/* now copy it, this also works without logicbricks! */
clear_sca_new_poins_ob(ob);
- copy_sensors(&base->object->sensors, &ob->sensors);
- copy_controllers(&base->object->controllers, &ob->controllers);
- copy_actuators(&base->object->actuators, &ob->actuators);
+ copy_sensors(&base->object->sensors, &ob->sensors, 0);
+ copy_controllers(&base->object->controllers, &ob->controllers, 0);
+ copy_actuators(&base->object->actuators, &ob->actuators, 0);
set_sca_new_poins_ob(base->object);
/* some menu settings */
@@ -933,7 +934,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
base->object->collision_boundtype = ob->collision_boundtype;
}
base->object->margin = ob->margin;
- base->object->bsoft = copy_bulletsoftbody(ob->bsoft);
+ base->object->bsoft = copy_bulletsoftbody(ob->bsoft, 0);
}
else if (event == 17) { /* tex space */
@@ -1041,7 +1042,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
base->object->softflag = ob->softflag;
if (base->object->soft) sbFree(base->object->soft);
- base->object->soft = copy_softbody(ob->soft, false);
+ base->object->soft = copy_softbody(ob->soft, 0);
if (!modifiers_findByType(base->object, eModifierType_Softbody)) {
BLI_addhead(&base->object->modifiers, modifier_new(eModifierType_Softbody));
@@ -1157,13 +1158,16 @@ void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object)
/* add/remove modifier as needed */
if (!md) {
- if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && ELEM(pd->forcefield, PFIELD_GUIDE, PFIELD_TEXTURE) == 0)
- if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE))
+ if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && !ELEM(pd->forcefield, 0, PFIELD_GUIDE, PFIELD_TEXTURE)) {
+ if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) {
ED_object_modifier_add(NULL, bmain, scene, object, NULL, eModifierType_Surface);
+ }
+ }
}
else {
- if (!pd || pd->shape != PFIELD_SHAPE_SURFACE || pd->forcefield != PFIELD_FORCE)
+ if (!pd || (pd->shape != PFIELD_SHAPE_SURFACE) || ELEM(pd->forcefield, 0, PFIELD_GUIDE, PFIELD_TEXTURE)) {
ED_object_modifier_remove(NULL, bmain, object, md);
+ }
}
}
@@ -2105,9 +2109,9 @@ static int logicbricks_copy_exec(bContext *C, wmOperator *UNUSED(op))
/* now copy it, this also works without logicbricks! */
clear_sca_new_poins_ob(ob);
- copy_sensors(&ob_iter->sensors, &ob->sensors);
- copy_controllers(&ob_iter->controllers, &ob->controllers);
- copy_actuators(&ob_iter->actuators, &ob->actuators);
+ copy_sensors(&ob_iter->sensors, &ob->sensors, 0);
+ copy_controllers(&ob_iter->controllers, &ob->controllers, 0);
+ copy_actuators(&ob_iter->actuators, &ob->actuators, 0);
set_sca_new_poins_ob(ob_iter);
/* some menu settings */
@@ -2168,7 +2172,7 @@ static int game_physics_copy_exec(bContext *C, wmOperator *UNUSED(op))
copy_v3_v3(ob_iter->anisotropicFriction, ob->anisotropicFriction);
ob_iter->collision_boundtype = ob->collision_boundtype;
ob_iter->margin = ob->margin;
- ob_iter->bsoft = copy_bulletsoftbody(ob->bsoft);
+ ob_iter->bsoft = copy_bulletsoftbody(ob->bsoft, 0);
if (ob->restrictflag & OB_RESTRICT_RENDER)
ob_iter->restrictflag |= OB_RESTRICT_RENDER;
else
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index 0fe43c44d7d..568778c0a86 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -528,8 +528,7 @@ static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op))
if (!group)
return OPERATOR_CANCELLED;
- BKE_libblock_unlink(bmain, group, false, false);
- BKE_libblock_free(bmain, group);
+ BKE_libblock_delete(bmain, group);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 9710e4f843d..b8957bdedf9 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -186,6 +186,7 @@ void OBJECT_OT_skin_loose_mark_clear(struct wmOperatorType *ot);
void OBJECT_OT_skin_radii_equalize(struct wmOperatorType *ot);
void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot);
void OBJECT_OT_laplaciandeform_bind(struct wmOperatorType *ot);
+void OBJECT_OT_surfacedeform_bind(struct wmOperatorType *ot);
/* object_constraint.c */
void OBJECT_OT_constraint_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index b44ddf925a8..1aa1407797b 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -98,12 +98,12 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
ModifierData *md = NULL, *new_md = NULL;
const ModifierTypeInfo *mti = modifierType_getInfo(type);
- /* only geometry objects should be able to get modifiers [#25291] */
- if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ /* Check compatibility of modifier [T25291, T50373]. */
+ if (!BKE_object_support_modifier_type_check(ob, type)) {
BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2);
return NULL;
}
-
+
if (mti->flags & eModifierTypeFlag_Single) {
if (modifiers_findByType(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
@@ -793,7 +793,7 @@ void OBJECT_OT_modifier_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add Modifier";
- ot->description = "Add a modifier to the active object";
+ ot->description = "Add a procedural operation/effect to the active object";
ot->idname = "OBJECT_OT_modifier_add";
/* api callbacks */
@@ -1484,7 +1484,6 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(ob);
BMesh *bm = em->bm;
- const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
BMVert *bm_vert;
BMIter bm_iter;
GSet *visited;
@@ -1493,6 +1492,8 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op))
BKE_mesh_ensure_skin_customdata(ob->data);
+ const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
+
BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT) &&
BLI_gset_add(visited, bm_vert))
@@ -2294,3 +2295,56 @@ void OBJECT_OT_laplaciandeform_bind(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
}
+
+/************************ sdef bind operator *********************/
+
+static int surfacedeform_bind_poll(bContext *C)
+{
+ return edit_modifier_poll_generic(C, &RNA_SurfaceDeformModifier, 0);
+}
+
+static int surfacedeform_bind_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_SurfaceDeform);
+
+ if (!smd)
+ return OPERATOR_CANCELLED;
+
+ if (smd->flags & MOD_SDEF_BIND) {
+ smd->flags &= ~MOD_SDEF_BIND;
+ }
+ else if (smd->target) {
+ smd->flags |= MOD_SDEF_BIND;
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int surfacedeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op))
+ return surfacedeform_bind_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_surfacedeform_bind(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Surface Deform Bind";
+ ot->description = "Bind mesh to target in surface deform modifier";
+ ot->idname = "OBJECT_OT_surfacedeform_bind";
+
+ /* api callbacks */
+ ot->poll = surfacedeform_bind_poll;
+ ot->invoke = surfacedeform_bind_invoke;
+ ot->exec = surfacedeform_bind_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 7e7e1ef182c..5fe5a884354 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -255,6 +255,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_data_transfer);
WM_operatortype_append(OBJECT_OT_datalayout_transfer);
+ WM_operatortype_append(OBJECT_OT_surfacedeform_bind);
}
void ED_operatormacros_object(void)
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index f448e925dd9..d5b516257a1 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -72,15 +72,18 @@
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_fcurve.h"
+#include "BKE_idprop.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_main.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_sca.h"
@@ -1578,13 +1581,13 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
break;
case MAKE_LINKS_ANIMDATA:
- BKE_animdata_copy_id((ID *)ob_dst, (ID *)ob_src, false);
+ BKE_animdata_copy_id(bmain, (ID *)ob_dst, (ID *)ob_src, false);
if (ob_dst->data && ob_src->data) {
if (ID_IS_LINKED_DATABLOCK(obdata_id)) {
is_lib = true;
break;
}
- BKE_animdata_copy_id((ID *)ob_dst->data, (ID *)ob_src->data, false);
+ BKE_animdata_copy_id(bmain, (ID *)ob_dst->data, (ID *)ob_src->data, false);
}
DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
break;
@@ -1731,6 +1734,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
/**************************** Make Single User ********************************/
+/* Warning, sets ID->newid pointers of objects and groups, but does not clear them. */
static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups)
{
Base *base;
@@ -1738,18 +1742,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
Group *group, *groupn;
GroupObject *go;
- clear_sca_new_poins(); /* sensor/contr/act */
-
- /* newid may still have some trash from Outliner tree building, so clear that first to avoid errors, see T26002.
- * We have to clear whole datablocks, not only Object one may be accessed here, see T49905. */
- ListBase *lbarray[MAX_LIBARRAY];
- int a = set_listbasepointers(bmain, lbarray);
- while (a--) {
- ListBase *lb = lbarray[a];
- for (ID *id = lb->first; id; id = id->next) {
- id->newid = NULL;
- }
- }
+ clear_sca_new_poins(); /* BGE logic */
/* duplicate (must set newid) */
for (base = FIRSTBASE; base; base = base->next) {
@@ -1758,8 +1751,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
if ((base->flag & flag) == flag) {
if (!ID_IS_LINKED_DATABLOCK(ob) && ob->id.us > 1) {
/* base gets copy of object */
- obn = BKE_object_copy(bmain, ob);
- base->object = obn;
+ base->object = obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
if (copy_groups) {
if (ob->flag & OB_FROMGROUP) {
@@ -1789,8 +1781,6 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
/* duplicate groups that consist entirely of duplicated objects */
for (group = bmain->group.first; group; group = group->id.next) {
- group->id.newid = NULL;
-
if (copy_groups && group->gobject.first) {
bool all_duplicated = true;
@@ -1802,10 +1792,11 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
}
if (all_duplicated) {
- groupn = BKE_group_copy(bmain, group);
+ groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group));
- for (go = groupn->gobject.first; go; go = go->next)
+ for (go = groupn->gobject.first; go; go = go->next) {
go->ob = (Object *)go->ob->id.newid;
+ }
}
}
}
@@ -1813,12 +1804,12 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
/* group pointers in scene */
BKE_scene_groups_relink(scene);
- ID_NEW(scene->camera);
- if (v3d) ID_NEW(v3d->camera);
+ ID_NEW_REMAP(scene->camera);
+ if (v3d) ID_NEW_REMAP(v3d->camera);
/* object and group pointers */
for (base = FIRSTBASE; base; base = base->next) {
- BKE_libblock_relink(&base->object->id);
+ BKE_libblock_relink_to_newid(&base->object->id);
}
set_sca_new_poins();
@@ -1837,6 +1828,8 @@ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
}
single_object_users(bmain, scene, NULL, OB_DONE, copy_groups);
+
+ BKE_main_id_clear_newpoins(bmain);
}
static void new_id_matar(Main *bmain, Material **matar, const int totcol)
@@ -1853,9 +1846,8 @@ static void new_id_matar(Main *bmain, Material **matar, const int totcol)
id_us_min(id);
}
else if (id->us > 1) {
- matar[a] = BKE_material_copy(bmain, matar[a]);
+ matar[a] = ID_NEW_SET(id, BKE_material_copy(bmain, matar[a]));
id_us_min(id);
- id->newid = (ID *)matar[a];
}
}
}
@@ -1883,45 +1875,46 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
switch (ob->type) {
case OB_LAMP:
- ob->data = la = BKE_lamp_copy(bmain, ob->data);
+ ob->data = la = ID_NEW_SET(ob->data, BKE_lamp_copy(bmain, ob->data));
for (a = 0; a < MAX_MTEX; a++) {
if (la->mtex[a]) {
- ID_NEW(la->mtex[a]->object);
+ ID_NEW_REMAP(la->mtex[a]->object);
}
}
break;
case OB_CAMERA:
- ob->data = BKE_camera_copy(bmain, ob->data);
+ ob->data = ID_NEW_SET(ob->data, BKE_camera_copy(bmain, ob->data));
break;
case OB_MESH:
- ob->data = me = BKE_mesh_copy(bmain, ob->data);
- if (me->key)
- BKE_animdata_copy_id_action((ID *)me->key);
+ /* Needed to remap texcomesh below. */
+ me = ob->data = ID_NEW_SET(ob->data, BKE_mesh_copy(bmain, ob->data));
+ if (me->key) /* We do not need to set me->key->id.newid here... */
+ BKE_animdata_copy_id_action((ID *)me->key, false);
break;
case OB_MBALL:
- ob->data = BKE_mball_copy(bmain, ob->data);
+ ob->data = ID_NEW_SET(ob->data, BKE_mball_copy(bmain, ob->data));
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
- ob->data = cu = BKE_curve_copy(bmain, ob->data);
- ID_NEW(cu->bevobj);
- ID_NEW(cu->taperobj);
- if (cu->key)
- BKE_animdata_copy_id_action((ID *)cu->key);
+ ob->data = cu = ID_NEW_SET(ob->data, BKE_curve_copy(bmain, ob->data));
+ ID_NEW_REMAP(cu->bevobj);
+ ID_NEW_REMAP(cu->taperobj);
+ if (cu->key) /* We do not need to set cu->key->id.newid here... */
+ BKE_animdata_copy_id_action((ID *)cu->key, false);
break;
case OB_LATTICE:
- ob->data = lat = BKE_lattice_copy(bmain, ob->data);
- if (lat->key)
- BKE_animdata_copy_id_action((ID *)lat->key);
+ ob->data = lat = ID_NEW_SET(ob->data, BKE_lattice_copy(bmain, ob->data));
+ if (lat->key) /* We do not need to set lat->key->id.newid here... */
+ BKE_animdata_copy_id_action((ID *)lat->key, false);
break;
case OB_ARMATURE:
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- ob->data = BKE_armature_copy(bmain, ob->data);
+ ob->data = ID_NEW_SET(ob->data, BKE_armature_copy(bmain, ob->data));
BKE_pose_rebuild(ob, ob->data);
break;
case OB_SPEAKER:
- ob->data = BKE_speaker_copy(bmain, ob->data);
+ ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data));
break;
default:
if (G.debug & G_DEBUG)
@@ -1934,17 +1927,16 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
* AnimData structure, which is not what we want.
* (sergey)
*/
- BKE_animdata_copy_id_action((ID *)ob->data);
+ BKE_animdata_copy_id_action((ID *)ob->data, false);
id_us_min(id);
- id->newid = ob->data;
}
}
}
me = bmain->mesh.first;
while (me) {
- ID_NEW(me->texcomesh);
+ ID_NEW_REMAP(me->texcomesh);
me = me->id.next;
}
}
@@ -1958,7 +1950,7 @@ static void single_object_action_users(Scene *scene, const int flag)
ob = base->object;
if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- BKE_animdata_copy_id_action(&ob->id);
+ BKE_animdata_copy_id_action(&ob->id, false);
}
}
}
@@ -1977,11 +1969,11 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo
for (a = 1; a <= ob->totcol; a++) {
ma = give_current_material(ob, a);
if (ma) {
- /* do not test for LIB_TAG_NEW: this functions guaranteed delivers single_users! */
+ /* do not test for LIB_TAG_NEW or use newid: this functions guaranteed delivers single_users! */
if (ma->id.us > 1) {
man = BKE_material_copy(bmain, ma);
- BKE_animdata_copy_id_action(&man->id);
+ BKE_animdata_copy_id_action(&man->id, false);
man->id.us = 0;
assign_material(ob, man, a, BKE_MAT_ASSIGN_USERPREF);
@@ -1992,7 +1984,7 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo
if (tex->id.us > 1) {
id_us_min(&tex->id);
tex = BKE_texture_copy(bmain, tex);
- BKE_animdata_copy_id_action(&tex->id);
+ BKE_animdata_copy_id_action(&tex->id, false);
man->mtex[b]->tex = tex;
}
}
@@ -2018,8 +2010,8 @@ static void do_single_tex_user(Main *bmain, Tex **from)
id_us_min(&tex->id);
}
else if (tex->id.us > 1) {
- texn = BKE_texture_copy(bmain, tex);
- BKE_animdata_copy_id_action(&texn->id);
+ texn = ID_NEW_SET(tex, BKE_texture_copy(bmain, tex));
+ BKE_animdata_copy_id_action(&texn->id, false);
tex->id.newid = (ID *)texn;
id_us_min(&tex->id);
*from = texn;
@@ -2096,7 +2088,7 @@ static void single_mat_users_expand(Main *bmain)
if (ma->id.tag & LIB_TAG_NEW)
for (a = 0; a < MAX_MTEX; a++)
if (ma->mtex[a])
- ID_NEW(ma->mtex[a]->object);
+ ID_NEW_REMAP(ma->mtex[a]->object);
}
/* used for copying scenes */
@@ -2111,30 +2103,54 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo
single_tex_users_expand(bmain);
}
- BKE_main_id_clear_newpoins(bmain);
- DAG_relations_tag_update(bmain);
-}
+ /* Relink nodetrees' pointers that have been duplicated. */
+ FOREACH_NODETREE(bmain, ntree, id)
+ {
+ /* This is a bit convoluted, we want to root ntree of copied IDs and only those,
+ * so we first check that old ID has been copied and that ntree is root tree of old ID,
+ * then get root tree of new ID and remap its pointers to new ID... */
+ if (id->newid && (&ntree->id != id)) {
+ ntree = ntreeFromID(id->newid);
+ BKE_libblock_relink_to_newid(&ntree->id);
+ }
+ } FOREACH_NODETREE_END
-/******************************* Make Local ***********************************/
+ /* Relink datablock pointer properties */
+ {
+ IDP_RelinkProperty(scene->id.properties);
-/* helper for below, ma was checked to be not NULL */
-static void make_local_makelocalmaterial(Material *ma)
-{
- AnimData *adt;
- int b;
+ for (Base *base = scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+ if (!ID_IS_LINKED_DATABLOCK(ob)) {
+ IDP_RelinkProperty(ob->id.properties);
+ }
+ }
- id_make_local(G.main, &ma->id, false, false);
+ if (scene->nodetree) {
+ IDP_RelinkProperty(scene->nodetree->id.properties);
+ for (bNode *node = scene->nodetree->nodes.first; node; node = node->next) {
+ IDP_RelinkProperty(node->prop);
+ }
+ }
- for (b = 0; b < MAX_MTEX; b++)
- if (ma->mtex[b] && ma->mtex[b]->tex)
- id_make_local(G.main, &ma->mtex[b]->tex->id, false, false);
+ if (scene->gpd) {
+ IDP_RelinkProperty(scene->gpd->id.properties);
+ }
- adt = BKE_animdata_from_id(&ma->id);
- if (adt) BKE_animdata_make_local(adt);
+ if (scene->world) {
+ IDP_RelinkProperty(scene->world->id.properties);
+ }
- /* nodetree? XXX */
+ if (scene->clip) {
+ IDP_RelinkProperty(scene->clip->id.properties);
+ }
+ }
+ BKE_main_id_clear_newpoins(bmain);
+ DAG_relations_tag_update(bmain);
}
+/******************************* Make Local ***********************************/
+
enum {
MAKE_LOCAL_SELECT_OB = 1,
MAKE_LOCAL_SELECT_OBDATA = 2,
@@ -2143,7 +2159,7 @@ enum {
};
static int tag_localizable_looper(
- void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int UNUSED(cd_flag))
+ void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int UNUSED(cb_flag))
{
if (*id_pointer) {
(*id_pointer)->tag &= ~LIB_TAG_DOIT;
@@ -2180,12 +2196,12 @@ static void tag_localizable_objects(bContext *C, const int mode)
*/
for (Object *object = bmain->object.first; object; object = object->id.next) {
if ((object->id.tag & LIB_TAG_DOIT) == 0) {
- BKE_library_foreach_ID_link(&object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(NULL, &object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
}
if (object->data) {
ID *data_id = (ID *) object->data;
if ((data_id->tag & LIB_TAG_DOIT) == 0) {
- BKE_library_foreach_ID_link(data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(NULL, data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
}
}
}
@@ -2220,123 +2236,142 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene)
return changed;
}
-static int make_local_exec(bContext *C, wmOperator *op)
+static void make_local_animdata_tag_strips(ListBase *strips)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- AnimData *adt;
- ParticleSystem *psys;
- Material *ma, ***matarar;
- Lamp *la;
- ID *id;
- const int mode = RNA_enum_get(op->ptr, "type");
- int a, b;
+ NlaStrip *strip;
- if (mode == MAKE_LOCAL_ALL) {
- /* de-select so the user can differentiate newly instanced from existing objects */
- BKE_scene_base_deselect_all(scene);
-
- if (make_local_all__instance_indirect_unused(bmain, scene)) {
- BKE_report(op->reports, RPT_INFO,
- "Orphan library objects added to the current scene to avoid loss");
+ for (strip = strips->first; strip; strip = strip->next) {
+ if (strip->act) {
+ strip->act->id.tag &= ~LIB_TAG_PRE_EXISTING;
+ }
+ if (strip->remap && strip->remap->target) {
+ strip->remap->target->id.tag &= ~LIB_TAG_PRE_EXISTING;
}
- BKE_library_make_local(bmain, NULL, NULL, false, false); /* NULL is all libs */
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- return OPERATOR_FINISHED;
+ make_local_animdata_tag_strips(&strip->strips);
}
+}
- tag_localizable_objects(C, mode);
- BKE_main_id_clear_newpoins(bmain);
-
- CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
- {
- if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
- continue;
+/* Tag all actions used by given animdata to be made local. */
+static void make_local_animdata_tag(AnimData *adt)
+{
+ if (adt) {
+ /* Actions - Active and Temp */
+ if (adt->action) {
+ adt->action->id.tag &= ~LIB_TAG_PRE_EXISTING;
+ }
+ if (adt->tmpact) {
+ adt->tmpact->id.tag &= ~LIB_TAG_PRE_EXISTING;
+ }
+ /* Remaps */
+ if (adt->remap && adt->remap->target) {
+ adt->remap->target->id.tag &= ~LIB_TAG_PRE_EXISTING;
}
- if (ob->id.lib)
- id_make_local(bmain, &ob->id, false, false);
- }
- CTX_DATA_END;
+ /* Drivers */
+ /* TODO: need to handle the ID-targets too? */
- /* maybe object pointers */
- CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
- {
- if (ob->id.lib == NULL) {
- ID_NEW(ob->parent);
+ /* NLA Data */
+ for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ make_local_animdata_tag_strips(&nlt->strips);
}
}
- CTX_DATA_END;
-
- CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
- {
- if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
- continue;
- }
+}
- id = ob->data;
+static void make_local_material_tag(Material *ma)
+{
+ if (ma) {
+ ma->id.tag &= ~LIB_TAG_PRE_EXISTING;
+ make_local_animdata_tag(BKE_animdata_from_id(&ma->id));
- if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) {
- id_make_local(bmain, id, false, false);
- adt = BKE_animdata_from_id(id);
- if (adt) BKE_animdata_make_local(adt);
+ /* About nodetrees: root one is made local together with material, others we keep linked for now... */
- /* tag indirect data direct */
- matarar = give_matarar(ob);
- if (matarar) {
- for (a = 0; a < ob->totcol; a++) {
- ma = (*matarar)[a];
- if (ma)
- id_lib_extern(&ma->id);
- }
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (ma->mtex[a] && ma->mtex[a]->tex) {
+ ma->mtex[a]->tex->id.tag &= ~LIB_TAG_PRE_EXISTING;
}
}
+ }
+}
+
+static int make_local_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ParticleSystem *psys;
+ Material *ma, ***matarar;
+ Lamp *la;
+ const int mode = RNA_enum_get(op->ptr, "type");
+ int a;
- for (psys = ob->particlesystem.first; psys; psys = psys->next)
- id_make_local(bmain, &psys->part->id, false, false);
+ /* Note: we (ab)use LIB_TAG_PRE_EXISTING to cherry pick which ID to make local... */
+ if (mode == MAKE_LOCAL_ALL) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* de-select so the user can differentiate newly instanced from existing objects */
+ BKE_scene_base_deselect_all(scene);
- adt = BKE_animdata_from_id(&ob->id);
- if (adt) BKE_animdata_make_local(adt);
+ if (make_local_all__instance_indirect_unused(bmain, scene)) {
+ BKE_report(op->reports, RPT_INFO, "Orphan library objects added to the current scene to avoid loss");
+ }
}
- CTX_DATA_END;
+ else {
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+ tag_localizable_objects(C, mode);
- if (mode == MAKE_LOCAL_SELECT_OBDATA_MATERIAL) {
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
continue;
}
- if (ob->type == OB_LAMP) {
- la = ob->data;
-
- for (b = 0; b < MAX_MTEX; b++)
- if (la->mtex[b] && la->mtex[b]->tex)
- id_make_local(bmain, &la->mtex[b]->tex->id, false, false);
+ ob->id.tag &= ~LIB_TAG_PRE_EXISTING;
+ make_local_animdata_tag(BKE_animdata_from_id(&ob->id));
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ psys->part->id.tag &= ~LIB_TAG_PRE_EXISTING;
}
- else {
+
+ if (mode == MAKE_LOCAL_SELECT_OBDATA_MATERIAL) {
for (a = 0; a < ob->totcol; a++) {
ma = ob->mat[a];
- if (ma)
- make_local_makelocalmaterial(ma);
+ if (ma) {
+ make_local_material_tag(ma);
+ }
}
matarar = (Material ***)give_matarar(ob);
if (matarar) {
for (a = 0; a < ob->totcol; a++) {
ma = (*matarar)[a];
- if (ma)
- make_local_makelocalmaterial(ma);
+ if (ma) {
+ make_local_material_tag(ma);
+ }
+ }
+ }
+
+ if (ob->type == OB_LAMP) {
+ BLI_assert(ob->data != NULL);
+ la = ob->data;
+ for (a = 0; a < MAX_MTEX; a++) {
+ if (la->mtex[a] && la->mtex[a]->tex) {
+ la->id.tag &= ~LIB_TAG_PRE_EXISTING;
+ }
}
}
}
+
+ if (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL) && ob->data != NULL) {
+ ID *ob_data = ob->data;
+ ob_data->tag &= ~LIB_TAG_PRE_EXISTING;
+ make_local_animdata_tag(BKE_animdata_from_id(ob_data));
+ }
}
CTX_DATA_END;
}
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ BKE_library_make_local(bmain, NULL, NULL, true, false); /* NULL is all libs */
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
}
@@ -2381,8 +2416,6 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
const bool copy_groups = false;
bool update_deps = false;
- BKE_main_id_clear_newpoins(bmain);
-
if (RNA_boolean_get(op->ptr, "object")) {
single_object_users(bmain, scene, v3d, flag, copy_groups);
@@ -2406,11 +2439,6 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
single_object_action_users(scene, flag);
}
- /* TODO(sergey): This should not be needed, however some tool still could rely
- * on the fact, that id->newid is kept NULL by default.
- * Need to make sure all the guys are learing newid before they're
- * using it, not after.
- */
BKE_main_id_clear_newpoins(bmain);
WM_event_add_notifier(C, NC_WINDOW, NULL);
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index f1b7186f8a1..b5131df3eaa 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -45,6 +45,7 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_rand.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -1131,7 +1132,7 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op)
{
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, primbase->object->id.name + 2, true);
+ BLI_string_flip_side_name(name_flip, primbase->object->id.name + 2, true, sizeof(name_flip));
if (!STREQ(name_flip, primbase->object->id.name + 2)) {
Object *ob = (Object *)BKE_libblock_find_name(ID_OB, name_flip);
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 4d7d7df0d2f..6491da4c23c 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -414,7 +414,10 @@ static void ignore_parent_tx(Main *bmain, Scene *scene, Object *ob)
}
}
-static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_loc, bool apply_rot, bool apply_scale)
+static int apply_objects_internal(
+ bContext *C, ReportList *reports,
+ bool apply_loc, bool apply_rot, bool apply_scale,
+ bool do_props)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -531,7 +534,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
BKE_mesh_calc_normals(me);
}
else if (ob->type == OB_ARMATURE) {
- ED_armature_apply_transform(ob, mat);
+ ED_armature_apply_transform(ob, mat, do_props);
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
@@ -540,12 +543,12 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
}
else if (ob->type == OB_MBALL) {
MetaBall *mb = ob->data;
- BKE_mball_transform(mb, mat);
+ BKE_mball_transform(mb, mat, do_props);
}
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = ob->data;
scale = mat3_to_scale(rsmat);
- BKE_curve_transform_ex(cu, mat, true, scale);
+ BKE_curve_transform_ex(cu, mat, true, do_props, scale);
}
else if (ob->type == OB_FONT) {
Curve *cu = ob->data;
@@ -561,7 +564,9 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
tb->h *= scale;
}
- cu->fsize *= scale;
+ if (do_props) {
+ cu->fsize *= scale;
+ }
}
else if (ob->type == OB_CAMERA) {
MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
@@ -677,9 +682,10 @@ static int object_transform_apply_exec(bContext *C, wmOperator *op)
const bool loc = RNA_boolean_get(op->ptr, "location");
const bool rot = RNA_boolean_get(op->ptr, "rotation");
const bool sca = RNA_boolean_get(op->ptr, "scale");
+ const bool do_props = RNA_boolean_get(op->ptr, "properties");
if (loc || rot || sca) {
- return apply_objects_internal(C, op->reports, loc, rot, sca);
+ return apply_objects_internal(C, op->reports, loc, rot, sca, do_props);
}
else {
/* allow for redo */
@@ -704,6 +710,8 @@ void OBJECT_OT_transform_apply(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "location", 0, "Location", "");
RNA_def_boolean(ot->srna, "rotation", 0, "Rotation", "");
RNA_def_boolean(ot->srna, "scale", 0, "Scale", "");
+ RNA_def_boolean(ot->srna, "properties", true, "Apply Properties",
+ "Modify properties such as curve vertex radius, font size and bone envelope");
}
/********************* Set Object Center ************************/
@@ -712,7 +720,8 @@ enum {
GEOMETRY_TO_ORIGIN = 0,
ORIGIN_TO_GEOMETRY,
ORIGIN_TO_CURSOR,
- ORIGIN_TO_CENTER_OF_MASS
+ ORIGIN_TO_CENTER_OF_MASS_SURFACE,
+ ORIGIN_TO_CENTER_OF_MASS_VOLUME,
};
static int object_origin_set_exec(bContext *C, wmOperator *op)
@@ -866,10 +875,21 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if (obedit == NULL && ob->type == OB_MESH) {
Mesh *me = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
- else if (centermode == ORIGIN_TO_CENTER_OF_MASS) { BKE_mesh_center_centroid(me, cent); }
- else if (around == V3D_AROUND_CENTER_MEAN) { BKE_mesh_center_median(me, cent); }
- else { BKE_mesh_center_bounds(me, cent); }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ /* done */
+ }
+ else if (centermode == ORIGIN_TO_CENTER_OF_MASS_SURFACE) {
+ BKE_mesh_center_of_surface(me, cent);
+ }
+ else if (centermode == ORIGIN_TO_CENTER_OF_MASS_VOLUME) {
+ BKE_mesh_center_of_volume(me, cent);
+ }
+ else if (around == V3D_AROUND_CENTER_MEAN) {
+ BKE_mesh_center_median(me, cent);
+ }
+ else {
+ BKE_mesh_center_bounds(me, cent);
+ }
negate_v3_v3(cent_neg, cent);
BKE_mesh_translate(me, cent_neg, 1);
@@ -923,8 +943,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
cent[2] = 0.0f;
- cu->xof = cu->xof - (cent[0] / cu->fsize);
- cu->yof = cu->yof - (cent[1] / cu->fsize);
+ cu->xof = cu->xof - cent[0];
+ cu->yof = cu->yof - cent[1];
tot_change++;
cu->id.tag |= LIB_TAG_DOIT;
@@ -1077,11 +1097,14 @@ void OBJECT_OT_origin_set(wmOperatorType *ot)
static EnumPropertyItem prop_set_center_types[] = {
{GEOMETRY_TO_ORIGIN, "GEOMETRY_ORIGIN", 0, "Geometry to Origin", "Move object geometry to object origin"},
{ORIGIN_TO_GEOMETRY, "ORIGIN_GEOMETRY", 0, "Origin to Geometry",
- "Move object origin to center of object geometry"},
+ "Calculate the center of geometry based on the current pivot point (median, otherwise bounding-box)"},
{ORIGIN_TO_CURSOR, "ORIGIN_CURSOR", 0, "Origin to 3D Cursor",
- "Move object origin to position of the 3D cursor"},
- {ORIGIN_TO_CENTER_OF_MASS, "ORIGIN_CENTER_OF_MASS", 0, "Origin to Center of Mass",
- "Move object origin to the object center of mass (assuming uniform density)"},
+ "Move object origin to position of the 3D cursor"},
+ /* Intentional naming mismatch since some scripts refer to this. */
+ {ORIGIN_TO_CENTER_OF_MASS_SURFACE, "ORIGIN_CENTER_OF_MASS", 0, "Origin to Center of Mass (Surface)",
+ "Calculate the center of mass from the surface area"},
+ {ORIGIN_TO_CENTER_OF_MASS_VOLUME, "ORIGIN_CENTER_OF_VOLUME", 0, "Origin to Center of Mass (Volume)",
+ "Calculate the center of mass from the volume (must be manifold geometry with consistent normals)"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 56f59dca9a1..584176e4b5d 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -50,7 +50,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_linklist_stack.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BKE_context.h"
@@ -238,6 +238,9 @@ bool ED_vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, co
}
return false;
}
+
+ default:
+ break;
}
}
@@ -363,8 +366,8 @@ void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array, const int dvert_tot
/* matching index only */
bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
{
- MDeformVert **dvert_array_from, **dvf;
- MDeformVert **dvert_array, **dv;
+ MDeformVert **dvert_array_from = NULL, **dvf;
+ MDeformVert **dvert_array = NULL, **dv;
int dvert_tot_from;
int dvert_tot;
int i;
@@ -375,26 +378,30 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
if (ob == ob_from)
return true;
- ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false);
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
-
- if ((dvert_array == NULL) && (dvert_array_from != NULL) && BKE_object_defgroup_data_create(ob->data)) {
+ /* in case we copy vgroup between two objects using same data, we only have to care about object side of things. */
+ if (ob->data != ob_from->data) {
+ ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false);
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
- new_vgroup = true;
- }
- if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL || dvert_array == NULL) {
+ if ((dvert_array == NULL) && (dvert_array_from != NULL) && BKE_object_defgroup_data_create(ob->data)) {
+ ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
+ new_vgroup = true;
+ }
- if (dvert_array) MEM_freeN(dvert_array);
- if (dvert_array_from) MEM_freeN(dvert_array_from);
+ if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL || dvert_array == NULL) {
+ if (dvert_array)
+ MEM_freeN(dvert_array);
+ if (dvert_array_from)
+ MEM_freeN(dvert_array_from);
- if (new_vgroup == true) {
- /* free the newly added vgroup since it wasn't compatible */
- BKE_object_defgroup_remove_all(ob);
- }
+ if (new_vgroup == true) {
+ /* free the newly added vgroup since it wasn't compatible */
+ BKE_object_defgroup_remove_all(ob);
+ }
- /* if true: both are 0 and nothing needs changing, consider this a success */
- return (dvert_tot == dvert_tot_from);
+ /* if true: both are 0 and nothing needs changing, consider this a success */
+ return (dvert_tot == dvert_tot_from);
+ }
}
/* do the copy */
@@ -412,22 +419,23 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
MEM_freeN(remap);
}
- dvf = dvert_array_from;
- dv = dvert_array;
+ if (dvert_array_from != NULL && dvert_array != NULL) {
+ dvf = dvert_array_from;
+ dv = dvert_array;
- for (i = 0; i < dvert_tot; i++, dvf++, dv++) {
- if ((*dv)->dw)
- MEM_freeN((*dv)->dw);
+ for (i = 0; i < dvert_tot; i++, dvf++, dv++) {
+ MEM_SAFE_FREE((*dv)->dw);
+ *(*dv) = *(*dvf);
- *(*dv) = *(*dvf);
+ if ((*dv)->dw) {
+ (*dv)->dw = MEM_dupallocN((*dv)->dw);
+ }
+ }
- if ((*dv)->dw)
- (*dv)->dw = MEM_dupallocN((*dv)->dw);
+ MEM_freeN(dvert_array);
+ MEM_freeN(dvert_array_from);
}
- MEM_freeN(dvert_array);
- MEM_freeN(dvert_array_from);
-
return true;
}
@@ -1707,17 +1715,11 @@ static void vgroup_invert_subset(Object *ob,
}
}
-enum {
- WEIGHT_SMOOTH_ALL = -1,
- WEIGHT_SMOOTH_DESELECT = false,
- WEIGHT_SMOOTH_SELECT = true,
-};
-
static void vgroup_smooth_subset(
Object *ob, const bool *vgroup_validmap, const int vgroup_tot,
const int subset_count,
const float fac, const int repeat,
- const float fac_expand, const int source)
+ const float fac_expand)
{
const float ifac = 1.0f - fac;
MDeformVert **dvert_array = NULL;
@@ -1725,6 +1727,8 @@ static void vgroup_smooth_subset(
int *vgroup_subset_map = BLI_array_alloca(vgroup_subset_map, subset_count);
float *vgroup_subset_weights = BLI_array_alloca(vgroup_subset_weights, subset_count);
const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false;
+ const bool use_select = vertex_group_use_vert_sel(ob);
+ const bool use_hide = use_select;
const int expand_sign = signum_i(fac_expand);
const float expand = fabsf(fac_expand);
@@ -1768,19 +1772,26 @@ static void vgroup_smooth_subset(
verts_used = MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__);
STACK_INIT(verts_used, dvert_tot);
+#define IS_BM_VERT_READ(v) \
+ (use_hide ? (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == 0) : true)
+#define IS_BM_VERT_WRITE(v) \
+ (use_select ? (BM_elem_flag_test(v, BM_ELEM_SELECT) != 0) : true)
+
+#define IS_ME_VERT_READ(v) \
+ (use_hide ? (((v)->flag & ME_HIDE) == 0) : true)
+#define IS_ME_VERT_WRITE(v) \
+ (use_select ? (((v)->flag & SELECT) != 0) : true)
/* initialize used verts */
if (bm) {
for (int i = 0; i < dvert_tot; i++) {
BMVert *v = BM_vert_at_index(bm, i);
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ if (IS_BM_VERT_WRITE(v)) {
BMIter eiter;
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
BMVert *v_other = BM_edge_other_vert(e, v);
- if ((source == WEIGHT_SMOOTH_ALL) ||
- (source == (BM_elem_flag_test(v_other, BM_ELEM_SELECT) != 0)))
- {
+ if (IS_BM_VERT_READ(v_other)) {
STACK_PUSH(verts_used, i);
break;
}
@@ -1790,13 +1801,12 @@ static void vgroup_smooth_subset(
}
else {
for (int i = 0; i < dvert_tot; i++) {
- MVert *v = &me->mvert[i];
- if (v->flag & SELECT) {
+ const MVert *v = &me->mvert[i];
+ if (IS_ME_VERT_WRITE(v)) {
for (int j = 0; j < emap[i].count; j++) {
- MVert *v_other = &me->mvert[emap[i].indices[j]];
- if ((source == WEIGHT_SMOOTH_ALL) ||
- (source == ((v_other->flag & SELECT) != 0)))
- {
+ const MEdge *e = &me->medge[emap[i].indices[j]];
+ const MVert *v_other = &me->mvert[(e->v1 == i) ? e->v2 : e->v1];
+ if (IS_ME_VERT_READ(v_other)) {
STACK_PUSH(verts_used, i);
break;
}
@@ -1849,13 +1859,11 @@ static void vgroup_smooth_subset(
BMEdge *e;
/* checked already */
- BLI_assert(BM_elem_flag_test(v, BM_ELEM_SELECT));
+ BLI_assert(IS_BM_VERT_WRITE(v));
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
BMVert *v_other = BM_edge_other_vert(e, v);
- if ((source == WEIGHT_SMOOTH_ALL) ||
- (source == (BM_elem_flag_test(v_other, BM_ELEM_SELECT) != 0)))
- {
+ if (IS_BM_VERT_READ(v_other)) {
const int i_other = BM_elem_index_get(v_other);
WEIGHT_ACCUMULATE;
@@ -1866,16 +1874,14 @@ static void vgroup_smooth_subset(
int j;
/* checked already */
- BLI_assert(me->mvert[i].flag & SELECT);
+ BLI_assert(IS_ME_VERT_WRITE(&me->mvert[i]));
for (j = 0; j < emap[i].count; j++) {
MEdge *e = &me->medge[emap[i].indices[j]];
const int i_other = (e->v1 == i ? e->v2 : e->v1);
MVert *v_other = &me->mvert[i_other];
- if ((source == WEIGHT_SMOOTH_ALL) ||
- (source == ((v_other->flag & SELECT) != 0)))
- {
+ if (IS_ME_VERT_READ(v_other)) {
WEIGHT_ACCUMULATE;
}
}
@@ -1899,6 +1905,11 @@ static void vgroup_smooth_subset(
ED_vgroup_parray_from_weight_array(dvert_array, dvert_tot, weight_accum_prev, def_nr, true);
}
+#undef IS_BM_VERT_READ
+#undef IS_BM_VERT_WRITE
+#undef IS_ME_VERT_READ
+#undef IS_ME_VERT_WRITE
+
MEM_freeN(weight_accum_curr);
MEM_freeN(weight_accum_prev);
MEM_freeN(verts_used);
@@ -2492,7 +2503,7 @@ static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext *C)
}
/* editmode _or_ weight paint vertex sel */
-static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_flag)
+static int vertex_group_vert_poll_ex(bContext *C, const bool needs_select, const short ob_type_flag)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
@@ -2508,12 +2519,17 @@ static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_fla
return true;
}
else if (ob->mode & OB_MODE_WEIGHT_PAINT) {
- if (BKE_object_is_in_wpaint_select_vert(ob)) {
- return true;
+ if (needs_select) {
+ if (BKE_object_is_in_wpaint_select_vert(ob)) {
+ return true;
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode");
+ return false;
+ }
}
else {
- CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode");
- return false;
+ return true;
}
}
else {
@@ -2521,15 +2537,31 @@ static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_fla
}
}
+#if 0
+static int vertex_group_vert_poll(bContext *C)
+{
+ return vertex_group_vert_poll_ex(C, false, 0);
+}
+#endif
+
+
+static int vertex_group_mesh_vert_poll(bContext *C)
+{
+ return vertex_group_vert_poll_ex(C, false, (1 << OB_MESH));
+}
+
static int vertex_group_vert_select_poll(bContext *C)
{
- return vertex_group_vert_select_poll_ex(C, 0);
+ return vertex_group_vert_poll_ex(C, true, 0);
}
+#if 0
static int vertex_group_mesh_vert_select_poll(bContext *C)
{
- return vertex_group_vert_select_poll_ex(C, (1 << OB_MESH));
+ return vertex_group_vert_poll_ex(C, true, (1 << OB_MESH));
}
+#endif
+
/* editmode _or_ weight paint vertex sel and active group unlocked */
static int vertex_group_vert_select_unlocked_poll(bContext *C)
@@ -3076,13 +3108,12 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op)
const float fac = RNA_float_get(op->ptr, "factor");
const int repeat = RNA_int_get(op->ptr, "repeat");
eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
- const int source = RNA_enum_get(op->ptr, "source");
const float fac_expand = RNA_float_get(op->ptr, "expand");
int subset_count, vgroup_tot;
const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
- vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand, source);
+ vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand);
MEM_freeN((void *)vgroup_validmap);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -3094,20 +3125,13 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op)
void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot)
{
- static EnumPropertyItem smooth_source_item[] = {
- {WEIGHT_SMOOTH_ALL, "ALL", 0, "All", ""},
- {WEIGHT_SMOOTH_SELECT, "SELECT", 0, "Only Selected", ""},
- {WEIGHT_SMOOTH_DESELECT, "DESELECT", 0, "Only Deselected", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
/* identifiers */
ot->name = "Smooth Vertex Weights";
ot->idname = "OBJECT_OT_vertex_group_smooth";
ot->description = "Smooth weights for selected vertices";
/* api callbacks */
- ot->poll = vertex_group_mesh_vert_select_poll;
+ ot->poll = vertex_group_mesh_vert_poll;
ot->exec = vertex_group_smooth_exec;
/* flags */
@@ -3118,7 +3142,6 @@ void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot)
RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
RNA_def_float(ot->srna, "expand", 0.0f, -1.0f, 1.0, "Expand/Contract", "Expand/contract weights", -1.0f, 1.0f);
- RNA_def_enum(ot->srna, "source", smooth_source_item, -1, "Source", "Vertices to mix with");
}
static int vertex_group_clean_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c
index 9f4da87903d..92b82e2a31b 100644
--- a/source/blender/editors/object/object_warp.c
+++ b/source/blender/editors/object/object_warp.c
@@ -53,8 +53,7 @@ static void object_warp_calc_view_matrix(float r_mat_view[4][4], float r_center_
float viewmat_roll[4][4];
/* apply the rotation offset by rolling the view */
- unit_m4(mat_offset);
- rotate_m4(mat_offset, 'Z', offset_angle);
+ axis_angle_to_mat4_single(mat_offset, 'Z', offset_angle);
mul_m4_m4m4(viewmat_roll, mat_offset, viewmat);
/* apply the view and the object matrix */
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 3d7a45843cc..edc3f6c784c 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -279,10 +279,10 @@ void DPAINT_OT_output_toggle(wmOperatorType *ot)
/***************************** Image Sequence Baking ******************************/
typedef struct DynamicPaintBakeJob {
- /* from wmJob */
- void *owner;
- short *stop, *do_update;
- float *progress;
+ /* from wmJob */
+ void *owner;
+ short *stop, *do_update;
+ float *progress;
struct Main *bmain;
Scene *scene;
@@ -297,13 +297,13 @@ typedef struct DynamicPaintBakeJob {
static void dpaint_bake_free(void *customdata)
{
- DynamicPaintBakeJob *job = customdata;
- MEM_freeN(job);
+ DynamicPaintBakeJob *job = customdata;
+ MEM_freeN(job);
}
static void dpaint_bake_endjob(void *customdata)
{
- DynamicPaintBakeJob *job = customdata;
+ DynamicPaintBakeJob *job = customdata;
DynamicPaintCanvasSettings *canvas = job->canvas;
canvas->flags &= ~MOD_DPAINT_BAKING;
@@ -311,7 +311,7 @@ static void dpaint_bake_endjob(void *customdata)
dynamicPaint_freeSurfaceData(job->surface);
G.is_rendering = false;
- BKE_spacedata_draw_locks(false);
+ BKE_spacedata_draw_locks(false);
WM_set_locked_interface(G.main->wm.first, false);
@@ -421,26 +421,26 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
- DynamicPaintBakeJob *job = customdata;
+ DynamicPaintBakeJob *job = customdata;
- job->stop = stop;
- job->do_update = do_update;
- job->progress = progress;
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
job->start = PIL_check_seconds_timer();
job->success = 1;
- G.is_break = false; /* reset BKE_blender_test_break*/
+ G.is_break = false; /* reset BKE_blender_test_break*/
/* XXX annoying hack: needed to prevent data corruption when changing
* scene frame in separate threads
- */
- G.is_rendering = true;
- BKE_spacedata_draw_locks(true);
+ */
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
dynamicPaint_bakeImageSequence(job);
- *do_update = true;
- *stop = 0;
+ *do_update = true;
+ *stop = 0;
}
/*
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index e22a145b3a6..72c5a74aee9 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -424,7 +424,6 @@ static bool PE_create_shape_tree(PEData *data, Object *shapeob)
return false;
}
- DM_ensure_looptri(dm);
return (bvhtree_from_mesh_looptri(&data->shape_bvh, dm, 0.0f, 4, 8) != NULL);
}
@@ -4419,7 +4418,7 @@ void PE_undo_push(Scene *scene, const char *str)
undo= undo->prev;
}
if (undo) {
- while (edit->undo.first!=undo) {
+ while (edit->undo.first != undo) {
PTCacheUndo *first= edit->undo.first;
BLI_remlink(&edit->undo, first);
free_PTCacheUndo(first);
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 4a4474868a2..29b652e1326 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -1035,7 +1035,7 @@ static bool copy_particle_systems_to_object(Main *bmain,
psys_from;
psys_from = PSYS_FROM_NEXT(psys_from), ++i) {
- psys = BKE_object_copy_particlesystem(psys_from);
+ psys = BKE_object_copy_particlesystem(psys_from, 0);
tmp_psys[i] = psys;
if (psys_start == NULL)
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index b5adf38527b..6460e83e2a0 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -631,71 +631,63 @@ static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDom
#define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp")
#define FLUID_SUFFIX_SURFACE "fluidsurface"
-static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetFile, char *debugStrBuffer)
+static bool fluid_init_filepaths(
+ ReportList *reports, FluidsimSettings *domainSettings, Object *fsDomain,
+ char *targetDir, char *targetFile)
{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim);
- FluidsimSettings *domainSettings= fluidmd->fss;
- FILE *fileCfg;
- int dirExist = 0;
- char newSurfdataPath[FILE_MAX]; /* modified output settings */
const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
- int outStringsChanged = 0;
/* prepare names... */
- const char *relbase= modifier_path_relbase(fsDomain);
+ const char *relbase = modifier_path_relbase(fsDomain);
+
+ /* We do not accept empty paths, they can end in random places silently, see T51176. */
+ if (domainSettings->surfdataPath[0] == '\0') {
+ modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath),
+ OB_FLUIDSIM_SURF_DIR_DEFAULT);
+ BKE_reportf(reports, RPT_WARNING, "Fluidsim: empty cache path, reset to default '%s'",
+ domainSettings->surfdataPath);
+ }
BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
- BLI_strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); /* if 0'd out below, this value is never used! */
- BLI_path_abs(targetDir, relbase); /* fixed #frame-no */
+ BLI_path_abs(targetDir, relbase);
/* .tmp: don't overwrite/delete original file */
BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
- // make sure all directories exist
- // as the bobjs use the same dir, this only needs to be checked
- // for the cfg output
- BLI_make_existing_file(targetFile);
-
- // check selected directory
- // simply try to open cfg file for writing to test validity of settings
- fileCfg = BLI_fopen(targetFile, "w");
- if (fileCfg) {
- dirExist = 1; fclose(fileCfg);
- // remove cfg dummy from directory test
- BLI_delete(targetFile, false, false);
- }
-
- if (targetDir[0] == '\0' || (!dirExist)) {
- char blendFile[FILE_MAX];
-
- // invalid dir, reset to current/previous
- BLI_split_file_part(G.main->name, blendFile, sizeof(blendFile));
- BLI_replace_extension(blendFile, FILE_MAX, ""); /* strip .blend */
- BLI_snprintf(newSurfdataPath, FILE_MAX, "//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
-
- BLI_snprintf(debugStrBuffer, 256, "fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
- elbeemDebugOut(debugStrBuffer);
- outStringsChanged=1;
- }
-
- /* check if modified output dir is ok */
-#if 0
- if (outStringsChanged) {
- char dispmsg[FILE_MAX+256];
- int selection=0;
- BLI_strncpy(dispmsg, "Output settings set to: '", sizeof(dispmsg));
- strcat(dispmsg, newSurfdataPath);
- strcat(dispmsg, "'%t|Continue with changed settings %x1|Discard and abort %x0");
-
- /* ask user if thats what he/she wants... */
- selection = pupmenu(dispmsg);
- if (selection < 1) return 0; /* 0 from menu, or -1 aborted */
- BLI_strncpy(targetDir, newSurfdataPath, sizeof(targetDir));
- strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR);
- BLI_path_abs(targetDir, G.main->name); /* fixed #frame-no */
+ /* Ensure whole path exists and is wirtable. */
+ const bool dir_exists = BLI_dir_create_recursive(targetDir);
+ const bool is_writable = BLI_file_is_writable(targetFile);
+
+ /* We change path to some presumably valid default value, but do not allow bake process to continue,
+ * this gives user chance to set manually another path. */
+ if (!dir_exists || !is_writable) {
+ modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath),
+ OB_FLUIDSIM_SURF_DIR_DEFAULT);
+
+ if (!dir_exists) {
+ BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not create cache directory '%s', reset to default '%s'",
+ targetDir, domainSettings->surfdataPath);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR, "Fluidsim: cache directory '%s' is not writable, reset to default '%s'",
+ targetDir, domainSettings->surfdataPath);
+ }
+
+ BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
+ BLI_path_abs(targetDir, relbase);
+
+ /* .tmp: don't overwrite/delete original file */
+ BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
+
+ /* Ensure whole path exists and is wirtable. */
+ if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) {
+ BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not use default cache directory '%s', "
+ "please define a valid cache path manually", targetDir);
+ }
+ return false;
}
-#endif
- return outStringsChanged;
+
+ return true;
}
/* ******************************************************************************** */
@@ -857,7 +849,6 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
char targetDir[FILE_MAX]; // store & modify output settings
char targetFile[FILE_MAX]; // temp. store filename from targetDir for access
- int outStringsChanged = 0; // modified? copy back before baking
float domainMat[4][4];
float invDomMat[4][4];
@@ -943,7 +934,11 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
/* ******** prepare output file paths ******** */
- outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer);
+ if (!fluid_init_filepaths(reports, domainSettings, fsDomain, targetDir, targetFile)) {
+ fluidbake_free_data(channels, fobjects, fsset, fb);
+ return false;
+ }
+
channels->length = scene->r.efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra)
channels->aniFrameTime = (double)((double)domainSettings->animEnd - (double)domainSettings->animStart) / (double)noFrames;
@@ -968,11 +963,6 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
/* ******** start writing / exporting ******** */
// use .tmp, don't overwrite/delete original file
BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp);
-
- // make sure these directories exist as well
- if (outStringsChanged) {
- BLI_make_existing_file(targetFile);
- }
/* ******** export domain to elbeem ******** */
elbeemResetSettings(fsset);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index 7ba4b2be43b..b1d708ebc07 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -137,8 +137,22 @@ static void keymap_particle(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "PARTICLE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "unselected", true);
- kmi = WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
+ /* Shift+LMB behavior first, so it has priority over KM_ANY item below. */
+ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "release_confirm", true);
+ RNA_boolean_set(kmi->ptr, "use_planar_constraint", true);
+ RNA_boolean_set(kmi->ptr, "use_accurate", false);
+
+ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "release_confirm", true);
+ RNA_boolean_set(kmi->ptr, "use_planar_constraint", false);
+ RNA_boolean_set(kmi->ptr, "use_accurate", true);
+
+ /* Using KM_ANY here to allow holding modifiers before starting to transform. */
+ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
+ RNA_boolean_set(kmi->ptr, "release_confirm", true);
+ RNA_boolean_set(kmi->ptr, "use_planar_constraint", false);
+ RNA_boolean_set(kmi->ptr, "use_accurate", false);
WM_keymap_add_item(keymap, "PARTICLE_OT_brush_edit", LEFTMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PARTICLE_OT_brush_edit", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c
index e81aa584586..f36ebb3715e 100644
--- a/source/blender/editors/physics/physics_pointcache.c
+++ b/source/blender/editors/physics/physics_pointcache.c
@@ -99,45 +99,45 @@ static int ptcache_job_break(void *customdata)
static void ptcache_job_update(void *customdata, float progress, int *cancel)
{
- PointCacheJob *job = customdata;
+ PointCacheJob *job = customdata;
- if (ptcache_job_break(job)) {
- *cancel = 1;
- }
+ if (ptcache_job_break(job)) {
+ *cancel = 1;
+ }
- *(job->do_update) = true;
- *(job->progress) = progress;
+ *(job->do_update) = true;
+ *(job->progress) = progress;
}
static void ptcache_job_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
- PointCacheJob *job = customdata;
+ PointCacheJob *job = customdata;
- job->stop = stop;
- job->do_update = do_update;
- job->progress = progress;
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
- G.is_break = false;
+ G.is_break = false;
- /* XXX annoying hack: needed to prevent data corruption when changing
- * scene frame in separate threads
- */
- G.is_rendering = true;
- BKE_spacedata_draw_locks(true);
+ /* XXX annoying hack: needed to prevent data corruption when changing
+ * scene frame in separate threads
+ */
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
BKE_ptcache_bake(job->baker);
- *do_update = true;
- *stop = 0;
+ *do_update = true;
+ *stop = 0;
}
static void ptcache_job_endjob(void *customdata)
{
- PointCacheJob *job = customdata;
+ PointCacheJob *job = customdata;
Scene *scene = job->baker->scene;
- G.is_rendering = false;
- BKE_spacedata_draw_locks(false);
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
WM_set_locked_interface(G.main->wm.first, false);
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 971ab9f3458..ec8bf3e955d 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -51,16 +51,6 @@ set(SRC
render_intern.h
)
-if(WITH_CODEC_QUICKTIME)
- list(APPEND INC
- ../../quicktime
- )
- list(APPEND INC_SYS
- ${QUICKTIME_INCLUDE_DIRS}
- )
- add_definitions(-DWITH_QUICKTIME)
-endif()
-
if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
endif()
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 8c5d25ad44d..ff64476a13c 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -116,6 +116,7 @@ typedef struct RenderJob {
ScrArea *sa;
ColorManagedViewSettings view_settings;
ColorManagedDisplaySettings display_settings;
+ bool supports_glsl_draw;
bool interface_locked;
} RenderJob;
@@ -210,7 +211,7 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
}
else {
if (rr->renlay == NULL) return;
- rectf = RE_RenderLayerGetPass(rr->renlay, SCE_PASS_COMBINED, viewname);
+ rectf = RE_RenderLayerGetPass(rr->renlay, RE_PASSNAME_COMBINED, viewname);
}
}
if (rectf == NULL) return;
@@ -304,7 +305,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- re = RE_NewRender(scene->id.name);
+ re = RE_NewSceneRender(scene);
lay_override = (v3d && v3d->lay != scene->lay) ? v3d->lay : 0;
G.is_break = false;
@@ -569,6 +570,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
* operate with.
*/
if (rr->do_exr_tile ||
+ !rj->supports_glsl_draw ||
ibuf->channels == 1 ||
U.image_draw_method != IMAGE_DRAW_METHOD_GLSL)
{
@@ -904,6 +906,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
rj->orig_layer = 0;
rj->last_layer = 0;
rj->sa = sa;
+ rj->supports_glsl_draw = IMB_colormanagement_support_glsl_draw(&scene->view_settings);
BKE_color_managed_display_settings_copy(&rj->display_settings, &scene->display_settings);
BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings);
@@ -961,7 +964,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
rj->image = ima;
/* setup new render */
- re = RE_NewRender(scene->id.name);
+ re = RE_NewSceneRender(scene);
RE_test_break_cb(re, rj, render_breakjob);
RE_draw_lock_cb(re, rj, render_drawlock);
RE_display_update_cb(re, rj, image_rect_update);
@@ -1168,7 +1171,7 @@ static void render_update_resolution(Render *re, const RenderPreview *rp,
}
if (rp->has_freestyle) {
- if (rp->resolution_divider == 1) {
+ if (rp->resolution_divider == BKE_render_preview_pixel_size(&rp->scene->r)) {
RE_ChangeModeFlag(re, R_EDGE_FRS, false);
}
else {
@@ -1234,7 +1237,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
use_border = render_view3d_disprect(rp->scene, rp->ar, rp->v3d,
rp->rv3d, &cliprct);
- if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE)) || rstats->convertdone == 0) {
+ if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE | PR_UPDATE_VIEW)) || rstats->convertdone == 0) {
RenderData rdata;
/* no osa, blur, seq, layers, savebuffer etc for preview render */
@@ -1309,11 +1312,12 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
RE_updateRenderInstances(re, ob_inst_update_flag);
for (;;) {
+ int pixel_size = BKE_render_preview_pixel_size(&rp->scene->r);
if (first_time == false) {
if (restore)
RE_DataBase_IncrementalView(re, rp->viewmat, 1);
- rp->resolution_divider /= 2;
+ rp->resolution_divider = MAX2(rp->resolution_divider / 2, pixel_size);
*do_update = 1;
render_update_resolution(re, rp, use_border, &cliprct);
@@ -1330,7 +1334,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
first_time = false;
- if (*stop || rp->resolution_divider == 1) {
+ if (*stop || rp->resolution_divider == pixel_size) {
break;
}
}
@@ -1432,7 +1436,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C)
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
int width = ar->winx, height = ar->winy;
- int divider = 1;
+ int divider = BKE_render_preview_pixel_size(&scene->r);
int resolution_threshold = scene->r.preview_start_resolution *
scene->r.preview_start_resolution;
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 9097432a251..a27026878e1 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -38,7 +38,6 @@
#include "BLI_math_color_blend.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLI_jitter.h"
#include "BLI_threads.h"
#include "BLI_task.h"
@@ -257,10 +256,8 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
}
- BLI_lock_thread(LOCK_DRAW_IMAGE);
if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd)))
oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
- BLI_unlock_thread(LOCK_DRAW_IMAGE);
/* will only work for non multiview correctly */
if (v3d) {
@@ -315,7 +312,7 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
IMB_freeImBuf(out);
}
- else if (gpd){
+ else if (gpd) {
/* If there are no strips, Grease Pencil still needs a buffer to draw on */
ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect);
RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
@@ -684,7 +681,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
}
/* create render */
- oglrender->re = RE_NewRender(scene->id.name);
+ oglrender->re = RE_NewSceneRender(scene);
/* create image and image user */
oglrender->ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
@@ -715,7 +712,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->task_scheduler = task_scheduler;
oglrender->task_pool = BLI_task_pool_create_background(task_scheduler,
oglrender);
- BLI_pool_set_num_threads(oglrender->task_pool, 1);
}
else {
oglrender->task_scheduler = NULL;
@@ -747,6 +743,23 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
int i;
if (oglrender->is_animation) {
+ /* Trickery part for movie output:
+ *
+ * We MUST write frames in an exact order, so we only let background
+ * thread to work on that, and main thread is simply waits for that
+ * thread to do all the dirty work.
+ *
+ * After this loop is done work_and_wait() will have nothing to do,
+ * so we don't run into wrong order of frames written to the stream.
+ */
+ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
+ BLI_mutex_lock(&oglrender->task_mutex);
+ while (oglrender->num_scheduled_frames > 0) {
+ BLI_condition_wait(&oglrender->task_condition,
+ &oglrender->task_mutex);
+ }
+ BLI_mutex_unlock(&oglrender->task_mutex);
+ }
BLI_task_pool_work_and_wait(oglrender->task_pool);
BLI_task_pool_free(oglrender->task_pool);
/* Depending on various things we might or might not use global scheduler. */
@@ -858,7 +871,7 @@ static bool screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
typedef struct WriteTaskData {
RenderResult *rr;
- int cfra;
+ Scene tmp_scene;
} WriteTaskData;
static void write_result_func(TaskPool * __restrict pool,
@@ -867,10 +880,10 @@ static void write_result_func(TaskPool * __restrict pool,
{
OGLRender *oglrender = (OGLRender *) BLI_task_pool_userdata(pool);
WriteTaskData *task_data = (WriteTaskData *) task_data_v;
- Scene *scene = oglrender->scene;
+ Scene *scene = &task_data->tmp_scene;
RenderResult *rr = task_data->rr;
const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
- const int cfra = task_data->cfra;
+ const int cfra = scene->r.cfra;
bool ok;
/* Don't attempt to write if we've got an error. */
if (!oglrender->pool_ok) {
@@ -886,18 +899,17 @@ static void write_result_func(TaskPool * __restrict pool,
*/
ReportList reports;
BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT);
- /* Do actual save logic here, depending on the file format. */
+ /* Do actual save logic here, depending on the file format.
+ *
+ * NOTE: We have to construct temporary scene with proper scene->r.cfra.
+ * This is because underlying calls do not use r.cfra but use scene
+ * for that.
+ */
if (is_movie) {
- /* We have to construct temporary scene with proper scene->r.cfra.
- * This is because underlying calls do not use r.cfra but use scene
- * for that.
- */
- Scene tmp_scene = *scene;
- tmp_scene.r.cfra = cfra;
ok = RE_WriteRenderViewsMovie(&reports,
rr,
- &tmp_scene,
- &tmp_scene.r,
+ scene,
+ &scene->r,
oglrender->mh,
oglrender->movie_ctx_arr,
oglrender->totvideos,
@@ -957,7 +969,7 @@ static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
Scene *scene = oglrender->scene;
WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data");
task_data->rr = rr;
- task_data->cfra = scene->r.cfra;
+ task_data->tmp_scene = *scene;
BLI_mutex_lock(&oglrender->task_mutex);
oglrender->num_scheduled_frames++;
if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
@@ -1071,7 +1083,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
/* render frame? */
if (oglrender->timer == event->customdata)
break;
- /* fall-through */
+ ATTR_FALLTHROUGH;
default:
/* nothing to do */
return OPERATOR_RUNNING_MODAL;
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 87c08dc6583..35d772afae7 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -196,7 +196,7 @@ static Main *load_main_from_memory(const void *blend, int blend_size)
BlendFileData *bfd;
G.fileflags |= G_FILE_NO_UI;
- bfd = BLO_read_from_memory(blend, blend_size, NULL);
+ bfd = BLO_read_from_memory(blend, blend_size, NULL, BLO_READ_SKIP_NONE);
if (bfd) {
bmain = bfd->main;
@@ -1180,7 +1180,7 @@ void ED_preview_icon_render(Main *bmain, Scene *scene, ID *id, unsigned int *rec
ip.bmain = bmain;
ip.scene = scene;
- ip.owner = id;
+ ip.owner = BKE_previewimg_id_ensure(id);
ip.id = id;
icon_preview_add_size(&ip, rect, sizex, sizey);
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 837573ad175..d252d764b42 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -611,7 +611,7 @@ void WORLD_OT_new(wmOperatorType *ot)
/* identifiers */
ot->name = "New World";
ot->idname = "WORLD_OT_new";
- ot->description = "Add a new world";
+ ot->description = "Create a new world Data-Block";
/* api callbacks */
ot->exec = new_world_exec;
@@ -1298,16 +1298,16 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op)
switch (freestyle_get_modifier_type(&ptr)) {
case LS_MODIFIER_TYPE_COLOR:
- BKE_linestyle_color_modifier_copy(lineset->linestyle, modifier);
+ BKE_linestyle_color_modifier_copy(lineset->linestyle, modifier, 0);
break;
case LS_MODIFIER_TYPE_ALPHA:
- BKE_linestyle_alpha_modifier_copy(lineset->linestyle, modifier);
+ BKE_linestyle_alpha_modifier_copy(lineset->linestyle, modifier, 0);
break;
case LS_MODIFIER_TYPE_THICKNESS:
- BKE_linestyle_thickness_modifier_copy(lineset->linestyle, modifier);
+ BKE_linestyle_thickness_modifier_copy(lineset->linestyle, modifier, 0);
break;
case LS_MODIFIER_TYPE_GEOMETRY:
- BKE_linestyle_geometry_modifier_copy(lineset->linestyle, modifier);
+ BKE_linestyle_geometry_modifier_copy(lineset->linestyle, modifier, 0);
break;
default:
BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
@@ -1781,6 +1781,8 @@ static void copy_mtex_copybuf(ID *id)
case ID_LS:
mtex = &(((FreestyleLineStyle *)id)->mtex[(int)((FreestyleLineStyle *)id)->texact]);
break;
+ default:
+ break;
}
if (mtex && *mtex) {
@@ -1818,7 +1820,7 @@ static void paste_mtex_copybuf(ID *id)
mtex = &(((FreestyleLineStyle *)id)->mtex[(int)((FreestyleLineStyle *)id)->texact]);
break;
default:
- BLI_assert("invalid id type");
+ BLI_assert(!"invalid id type");
return;
}
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index f11a8177bf8..4e02ff77a31 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -189,8 +189,12 @@ void ED_render_engine_changed(Main *bmain)
RE_FreePersistentData();
- for (scene = bmain->scene.first; scene; scene = scene->id.next)
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
ED_render_id_flush_update(bmain, &scene->id);
+ if (scene->nodetree) {
+ ntreeCompositUpdateRLayers(scene->nodetree);
+ }
+ }
}
/***************************** Updates ***********************************
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 65f0fec50bc..c4a9af79ec2 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -44,6 +44,7 @@
#include "WM_types.h"
#include "ED_screen.h"
+#include "UI_interface.h"
#include "wm_window.h"
@@ -128,8 +129,8 @@ static ScrArea *find_area_image_empty(bContext *C)
/* new window uses x,y to set position */
ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
{
- wmWindow *win = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
+ wmWindow *win = NULL;
ScrArea *sa = NULL;
SpaceImage *sima;
bool area_was_image = false;
@@ -138,25 +139,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
return NULL;
if (scene->r.displaymode == R_OUTPUT_WINDOW) {
- rcti rect;
- int sizex, sizey;
-
- sizex = 10 + (scene->r.xsch * scene->r.size) / 100;
- sizey = 40 + (scene->r.ysch * scene->r.size) / 100;
+ int sizex = 30 * UI_DPI_FAC + (scene->r.xsch * scene->r.size) / 100;
+ int sizey = 60 * UI_DPI_FAC + (scene->r.ysch * scene->r.size) / 100;
/* arbitrary... miniature image window views don't make much sense */
if (sizex < 320) sizex = 320;
if (sizey < 256) sizey = 256;
- /* some magic to calculate postition */
- /* pixelsize: mouse coords are in U.pixelsize units :/ */
- rect.xmin = (mx / U.pixelsize) + win->posx - sizex / 2;
- rect.ymin = (my / U.pixelsize) + win->posy - sizey / 2;
- rect.xmax = rect.xmin + sizex;
- rect.ymax = rect.ymin + sizey;
-
/* changes context! */
- if (WM_window_open_temp(C, &rect, WM_WINDOW_RENDER) == NULL) {
+ if (WM_window_open_temp(C, mx, my, sizex, sizey, WM_WINDOW_RENDER) == NULL) {
BKE_report(reports, RPT_ERROR, "Failed to open window!");
return NULL;
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index e6bb604d387..9cfaf3b4c1d 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1749,7 +1749,7 @@ int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
RNA_pointer_create(&(scr->id), &RNA_Area, sa, &areaptr);
- uiDefButR(block, UI_BTYPE_MENU, 0, "", xco, yco, 1.5 * U.widget_unit, U.widget_unit,
+ uiDefButR(block, UI_BTYPE_MENU, 0, "", xco, yco, 1.6 * U.widget_unit, U.widget_unit,
&areaptr, "type", 0, 0.0f, 0.0f, 0.0f, 0.0f, "");
return xco + 1.7 * U.widget_unit;
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 93bac3f6660..216cbe9d7f4 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -566,7 +566,7 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
float rast_x = x + off_x * xzoom;
float rast_y = y + off_y * yzoom;
- GLfloat scissor[4];
+ GLfloat viewport[4];
int draw_w, draw_h;
/* Determine the smallest number of pixels we need to draw
@@ -581,9 +581,9 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
* fails if we zoom in on one really huge pixel so that it
* covers the entire screen).
*/
- glGetFloatv(GL_SCISSOR_BOX, scissor);
- draw_w = min_ii(img_w - off_x, ceil((scissor[2] - rast_x) / xzoom));
- draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom));
+ glGetFloatv(GL_VIEWPORT, viewport);
+ draw_w = min_ii(img_w - off_x, ceil((viewport[2] - rast_x) / xzoom));
+ draw_h = min_ii(img_h - off_y, ceil((viewport[3] - rast_y) / yzoom));
if (draw_w > 0 && draw_h > 0) {
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index c165bbfd301..1190423e2f1 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -54,6 +54,7 @@
#include "ED_armature.h"
#include "ED_gpencil.h"
+#include "ED_anim_api.h"
#include "WM_api.h"
#include "UI_interface.h"
@@ -87,7 +88,7 @@ const char *screen_context_dir[] = {
"visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes",
"active_gpencil_layer", "active_gpencil_frame", "active_gpencil_palette",
"active_gpencil_palettecolor", "active_gpencil_brush",
- "active_operator",
+ "active_operator", "selected_editable_fcurves",
NULL};
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
@@ -608,6 +609,29 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
}
+ else if (CTX_data_equals(member, "selected_editable_fcurves")) {
+ bAnimContext ac;
+
+ if (ANIM_animdata_get_context(C, &ac) && ELEM(ac.spacetype, SPACE_ACTION, SPACE_IPO)) {
+ bAnimListElem *ale;
+ ListBase anim_data = {NULL, NULL};
+
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS | ANIMFILTER_SEL) |
+ (ac.spacetype == SPACE_IPO ? ANIMFILTER_CURVE_VISIBLE : ANIMFILTER_LIST_VISIBLE);
+
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ if (ale->type == ANIMTYPE_FCURVE)
+ CTX_data_list_add(result, ale->id, &RNA_FCurve, ale->data);
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ }
else {
return 0; /* not found */
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 5cd0d33c365..8f1132dc1e5 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -467,7 +467,7 @@ bScreen *ED_screen_add(wmWindow *win, Scene *scene, const char *name)
bScreen *sc;
ScrVert *sv1, *sv2, *sv3, *sv4;
- sc = BKE_libblock_alloc(G.main, ID_SCR, name);
+ sc = BKE_libblock_alloc(G.main, ID_SCR, name, 0);
sc->scene = scene;
sc->do_refresh = true;
sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
@@ -766,7 +766,9 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
/* lower edge */
const int yval = sa->v2->vec.y - headery_init;
se = screen_findedge(sc, sa->v4, sa->v1);
- select_connected_scredge(sc, se);
+ if (se != NULL) {
+ select_connected_scredge(sc, se);
+ }
for (sv = sc->vertbase.first; sv; sv = sv->next) {
if (sv != sa->v2 && sv != sa->v3) {
if (sv->flag) {
@@ -779,7 +781,9 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
/* upper edge */
const int yval = sa->v1->vec.y + headery_init;
se = screen_findedge(sc, sa->v2, sa->v3);
- select_connected_scredge(sc, se);
+ if (se != NULL) {
+ select_connected_scredge(sc, se);
+ }
for (sv = sc->vertbase.first; sv; sv = sv->next) {
if (sv != sa->v1 && sv != sa->v4) {
if (sv->flag) {
@@ -1224,6 +1228,7 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
winrct.ymax = winsize_y - 1;
/* header size depends on DPI, let's verify */
+ WM_window_set_dpi(win);
screen_refresh_headersizes();
screen_test_scale(win->screen, winsize_x, winsize_y);
@@ -1358,7 +1363,7 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
/* *********************************** */
/* case when on area-edge or in azones, or outside window */
-static void screen_cursor_set(wmWindow *win, wmEvent *event)
+static void screen_cursor_set(wmWindow *win, const wmEvent *event)
{
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
@@ -1397,7 +1402,7 @@ static void screen_cursor_set(wmWindow *win, wmEvent *event)
/* called in wm_event_system.c. sets state vars in screen, cursors */
/* event type is mouse move */
-void ED_screen_set_subwinactive(bContext *C, wmEvent *event)
+void ED_screen_set_subwinactive(bContext *C, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
@@ -1758,7 +1763,10 @@ bool ED_screen_delete_scene(bContext *C, Scene *scene)
BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
- BKE_libblock_free(bmain, scene);
+ id_us_clear_real(&scene->id);
+ if (scene->id.us == 0) {
+ BKE_libblock_free(bmain, scene);
+ }
return true;
}
@@ -1889,17 +1897,28 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
if (sa && sa->full) {
/* restoring back to SCREENNORMAL */
- ScrArea *old;
-
sc = sa->full; /* the old screen to restore */
oldscreen = win->screen; /* the one disappearing */
sc->state = SCREENNORMAL;
- /* find old area */
- for (old = sc->areabase.first; old; old = old->next)
- if (old->full) break;
- if (old == NULL) {
+ /* find old area to restore from */
+ ScrArea *fullsa = NULL;
+ for (ScrArea *old = sc->areabase.first; old; old = old->next) {
+ /* area to restore from is always first */
+ if (old->full && !fullsa) {
+ fullsa = old;
+ }
+
+ /* clear full screen state */
+ old->full = NULL;
+ old->flag &= ~AREA_TEMP_INFO;
+ }
+
+ sa->flag &= ~AREA_TEMP_INFO;
+ sa->full = NULL;
+
+ if (fullsa == NULL) {
if (G.debug & G_DEBUG)
printf("%s: something wrong in areafullscreen\n", __func__);
return NULL;
@@ -1912,9 +1931,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
}
- ED_area_data_swap(old, sa);
- if (sa->flag & AREA_TEMP_INFO) sa->flag &= ~AREA_TEMP_INFO;
- old->full = NULL;
+ ED_area_data_swap(fullsa, sa);
/* animtimer back */
sc->animtimer = oldscreen->animtimer;
@@ -1922,7 +1939,6 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
ED_screen_set(C, sc);
- BKE_screen_free(oldscreen);
BKE_libblock_free(CTX_data_main(C), oldscreen);
/* After we've restored back to SCREENNORMAL, we have to wait with
@@ -2166,10 +2182,11 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
/* update animated texture nodes */
{
Tex *tex;
- for (tex = bmain->tex.first; tex; tex = tex->id.next)
+ for (tex = bmain->tex.first; tex; tex = tex->id.next) {
if (tex->use_nodes && tex->nodetree) {
ntreeTexTagAnimated(tex->nodetree);
}
+ }
}
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index c69e01422e0..27e19ca1fc3 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -2260,25 +2260,28 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
BLI_dlrbTree_linkedlist_sync(&keys);
/* find matching keyframe in the right direction */
- do {
- if (next)
- ak = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfra);
- else
- ak = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfra);
-
- if (ak) {
- if (CFRA != (int)ak->cfra) {
- /* this changes the frame, so set the frame and we're done */
- CFRA = (int)ak->cfra;
- done = true;
+ if (next)
+ ak = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfra);
+ else
+ ak = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfra);
+
+ while ((ak != NULL) && (done == false)) {
+ if (CFRA != (int)ak->cfra) {
+ /* this changes the frame, so set the frame and we're done */
+ CFRA = (int)ak->cfra;
+ done = true;
+ }
+ else {
+ /* take another step... */
+ if (next) {
+ ak = ak->next;
}
else {
- /* make this the new starting point for the search */
- cfra = ak->cfra;
+ ak = ak->prev;
}
}
- } while ((ak != NULL) && (done == false));
-
+ }
+
/* free temp stuff */
BLI_dlrbTree_free(&keys);
@@ -2808,7 +2811,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
bScreen *sc = CTX_wm_screen(C);
uiPopupMenu *pup;
uiLayout *layout;
- PointerRNA ptr1, ptr2;
+ PointerRNA ptr;
ScrEdge *actedge;
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
@@ -2820,22 +2823,17 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
layout = UI_popup_menu_layout(pup);
- WM_operator_properties_create(&ptr1, "SCREEN_OT_area_join");
-
- /* mouse cursor on edge, '4' can fail on wide edges... */
- RNA_int_set(&ptr1, "min_x", event->x + 4);
- RNA_int_set(&ptr1, "min_y", event->y + 4);
- RNA_int_set(&ptr1, "max_x", event->x - 4);
- RNA_int_set(&ptr1, "max_y", event->y - 4);
-
- WM_operator_properties_create(&ptr2, "SCREEN_OT_area_split");
-
+ ptr = uiItemFullO(layout, "SCREEN_OT_area_split", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
/* store initial mouse cursor position */
- RNA_int_set(&ptr2, "mouse_x", event->x);
- RNA_int_set(&ptr2, "mouse_y", event->y);
-
- uiItemFullO(layout, "SCREEN_OT_area_split", NULL, ICON_NONE, ptr2.data, WM_OP_INVOKE_DEFAULT, 0);
- uiItemFullO(layout, "SCREEN_OT_area_join", NULL, ICON_NONE, ptr1.data, WM_OP_INVOKE_DEFAULT, 0);
+ RNA_int_set(&ptr, "mouse_x", event->x);
+ RNA_int_set(&ptr, "mouse_y", event->y);
+
+ ptr = uiItemFullO(layout, "SCREEN_OT_area_join", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ /* mouse cursor on edge, '4' can fail on wide edges... */
+ RNA_int_set(&ptr, "min_x", event->x + 4);
+ RNA_int_set(&ptr, "min_y", event->y + 4);
+ RNA_int_set(&ptr, "max_x", event->x - 4);
+ RNA_int_set(&ptr, "max_y", event->y - 4);
UI_popup_menu_end(C, pup);
@@ -2903,10 +2901,23 @@ static void SCREEN_OT_spacedata_cleanup(wmOperatorType *ot)
static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op))
{
- wmOperator *lastop = CTX_wm_manager(C)->operators.last;
-
- if (lastop)
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmOperator *lastop = wm->operators.last;
+
+ /* Seek last registered operator */
+ while (lastop) {
+ if (lastop->type->flag & OPTYPE_REGISTER) {
+ break;
+ }
+ else {
+ lastop = lastop->prev;
+ }
+ }
+
+ if (lastop) {
+ WM_operator_free_all_after(wm, lastop);
WM_operator_repeat(C, lastop);
+ }
return OPERATOR_CANCELLED;
}
@@ -2941,8 +2952,9 @@ static int repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
layout = UI_popup_menu_layout(pup);
for (i = items - 1, lastop = wm->operators.last; lastop; lastop = lastop->prev, i--)
- if (WM_operator_repeat_check(C, lastop))
+ if ((lastop->type->flag & OPTYPE_REGISTER) && WM_operator_repeat_check(C, lastop)) {
uiItemIntO(layout, RNA_struct_ui_name(lastop->type->srna), ICON_NONE, op->type->idname, "index", i);
+ }
UI_popup_menu_end(C, pup);
@@ -3747,7 +3759,7 @@ static int screen_animation_cancel_exec(bContext *C, wmOperator *op)
bScreen *screen = ED_screen_animation_playing(CTX_wm_manager(C));
if (screen) {
- if (RNA_boolean_get(op->ptr, "restore_frame")) {
+ if (RNA_boolean_get(op->ptr, "restore_frame") && screen->animtimer) {
ScreenAnimData *sad = screen->animtimer->customdata;
Scene *scene = CTX_data_scene(C);
@@ -3874,22 +3886,11 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- wmWindow *win = CTX_wm_window(C);
- rcti rect;
- int sizex, sizey;
-
- sizex = 800 * UI_DPI_WINDOW_FAC;
- sizey = 480 * UI_DPI_WINDOW_FAC;
-
- /* some magic to calculate postition */
- /* pixelsize: mouse coords are in U.pixelsize units :/ */
- rect.xmin = (event->x / U.pixelsize) + win->posx - sizex / 2;
- rect.ymin = (event->y / U.pixelsize) + win->posy - sizey / 2;
- rect.xmax = rect.xmin + sizex;
- rect.ymax = rect.ymin + sizey;
+ int sizex = 800 * UI_DPI_FAC;
+ int sizey = 480 * UI_DPI_FAC;
/* changes context! */
- if (WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS) != NULL) {
+ if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_USERPREFS) != NULL) {
return OPERATOR_FINISHED;
}
else {
@@ -4329,6 +4330,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(ED_OT_undo);
WM_operatortype_append(ED_OT_undo_push);
WM_operatortype_append(ED_OT_redo);
+ WM_operatortype_append(ED_OT_undo_redo);
WM_operatortype_append(ED_OT_undo_history);
WM_operatortype_append(ED_OT_flush_edits);
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 46753df4e13..69f14c950bb 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -52,6 +52,10 @@ set(SRC
paint_undo.c
paint_utils.c
paint_vertex.c
+ paint_vertex_color_ops.c
+ paint_vertex_color_utils.c
+ paint_vertex_weight_ops.c
+ paint_vertex_weight_utils.c
paint_vertex_proj.c
sculpt.c
sculpt_undo.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 53c11e2a6a9..0cf39644bc1 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -42,6 +42,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
#include "BKE_brush.h"
#include "BKE_context.h"
@@ -1002,8 +1003,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
* mouse over too, not just during a stroke */
view3d_set_viewcontext(C, &vc);
- get_imapaint_zoom(C, &zoomx, &zoomy);
- zoomx = max_ff(zoomx, zoomy);
+ if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
+ return;
+ }
/* skip everything and draw brush here */
if (brush->flag & BRUSH_CURVE) {
@@ -1011,6 +1013,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
return;
}
+ get_imapaint_zoom(C, &zoomx, &zoomy);
+ zoomx = max_ff(zoomx, zoomy);
+
/* set various defaults */
translation[0] = x;
translation[1] = y;
@@ -1043,11 +1048,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* check if brush is subtracting, use different color then */
/* TODO: no way currently to know state of pen flip or
* invert key modifier without starting a stroke */
- if (((ups->draw_inverted == 0) ^
- ((brush->flag & BRUSH_DIR_IN) == 0)) &&
- ELEM(brush->sculpt_tool, SCULPT_TOOL_DRAW,
- SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
- SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE))
+ if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
+ BKE_brush_sculpt_has_secondary_color(brush))
{
outline_col = brush->sub_col;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index bf344e1f721..79ce440251d 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -1448,7 +1448,20 @@ void PAINT_OT_texture_paint_toggle(wmOperatorType *ot)
static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op))
{
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- Brush *br = image_paint_brush(C);
+
+ Brush *br;
+ Object *ob = CTX_data_active_object(C);
+ if (!(ob && (ob->mode & OB_MODE_VERTEX_PAINT))) {
+ br = image_paint_brush(C);
+ }
+ else {
+ /* At the moment, wpaint does not support the color flipper.
+ * So for now we're only handling vpaint */
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ VPaint *vp = ts->vpaint;
+ br = BKE_paint_brush(&vp->paint);
+ }
+
if (ups->flag & UNIFIED_PAINT_COLOR) {
swap_v3_v3(ups->rgb, ups->secondary_rgb);
}
@@ -1467,7 +1480,12 @@ static int brush_colors_flip_poll(bContext *C)
if (br->imagepaint_tool == PAINT_TOOL_DRAW)
return 1;
}
-
+ else {
+ Object *ob = CTX_data_active_object(C);
+ if (ob && (ob->mode & OB_MODE_VERTEX_PAINT)) {
+ return 1;
+ }
+ }
return 0;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 4f93c12385d..09b0847b306 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -797,6 +797,7 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus
float map_alpha = (rgb[3] == 0.0f) ? rrgbf[3] : rrgbf[3] / rgb[3];
mul_v3_v3fl(rrgbf, rgb, map_alpha);
+ rrgbf[3] = rgb[3];
}
else {
unsigned char straight[4];
@@ -806,6 +807,7 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus
rrgb[0] = straight[0];
rrgb[1] = straight[1];
rrgb[2] = straight[2];
+ rrgb[3] = straight[3];
}
}
@@ -995,7 +997,7 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short tile)
IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, NULL, 0, region[a].destx, region[a].desty,
region[a].destx, region[a].desty,
region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, IMB_BLEND_COPY_RGB, false);
+ region[a].width, region[a].height, IMB_BLEND_COPY, false);
}
static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
@@ -1096,6 +1098,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
/* lift from canvas */
if (s->tool == PAINT_TOOL_SOFTEN) {
paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile);
+ blend = IMB_BLEND_INTERPOLATE;
}
else if (s->tool == PAINT_TOOL_SMEAR) {
if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
@@ -1103,6 +1106,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
paint_2d_convert_brushco(ibufb, lastpos, blastpos);
paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile);
+ blend = IMB_BLEND_INTERPOLATE;
}
else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
liftpos[0] = pos[0] - offset[0] * s->canvas->x;
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index f5d115442c6..8586eb42bec 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -3712,8 +3712,12 @@ static void project_paint_prepare_all_faces(
}
/* don't allow using the same inage for painting and stencilling */
- if (slot->ima == ps->stencil_ima)
+ if (slot->ima == ps->stencil_ima) {
+ /* While this shouldn't be used, face-winding reads all polys.
+ * It's less trouble to set all faces to valid UV's, avoiding NULL checks all over. */
+ ps->dm_mloopuv[lt->poly] = mloopuv_base;
continue;
+ }
tpage = slot->ima;
}
@@ -4291,7 +4295,7 @@ static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, f
return;
}
else {
- blend_color_interpolate_float(rgba, rgba, projPixel->pixel.f_pt, mask);
+ blend_color_interpolate_float(rgba, projPixel->pixel.f_pt, rgba, mask);
}
BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
@@ -4750,6 +4754,9 @@ static void *do_projectpaint_thread(void *ph_v)
copy_v3_v3(texrgb, texrgba);
mask *= texrgba[3];
}
+ else {
+ zero_v3(texrgb);
+ }
/* extra mask for normal, layer stencil, .. */
mask *= ((float)projPixel->mask) * (1.0f / 65535.0f);
@@ -5711,21 +5718,16 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
/* successful creation of mtex layer, now create set */
if (mtex) {
int type = MAP_COL;
- int type_id = 0;
+ char imagename_buff[MAX_ID_NAME - 2];
+ const char *imagename = DATA_("Diffuse Color");
if (op) {
- int i;
type = RNA_enum_get(op->ptr, "type");
-
- for (i = 0; i < ARRAY_SIZE(layer_type_items); i++) {
- if (layer_type_items[i].value == type) {
- type_id = i;
- break;
- }
- }
+ RNA_string_get(op->ptr, "name", imagename_buff);
+ imagename = imagename_buff;
}
- mtex->tex = BKE_texture_add(bmain, DATA_(layer_type_items[type_id].name));
+ mtex->tex = BKE_texture_add(bmain, imagename);
mtex->mapto = type;
if (mtex->tex) {
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 7e05ab929ae..f6fcbfdfbee 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -96,21 +96,11 @@ int weight_paint_mode_poll(struct bContext *C);
int vertex_paint_poll(struct bContext *C);
int vertex_paint_mode_poll(struct bContext *C);
-bool ED_vpaint_fill(struct Object *ob, unsigned int paintcol);
-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);
-void PAINT_OT_weight_from_bones(struct wmOperatorType *ot);
-void PAINT_OT_weight_sample(struct wmOperatorType *ot);
-void PAINT_OT_weight_sample_group(struct wmOperatorType *ot);
enum {
WPAINT_GRADIENT_TYPE_LINEAR,
@@ -123,6 +113,44 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp);
+/* paint_vertex_color_utils.c */
+unsigned int ED_vpaint_blend_tool(
+ const int tool, const uint col,
+ const uint paintcol, const int alpha_i);
+bool ED_vpaint_color_transform(
+ struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data);
+
+/* paint_vertex_weight_utils.c */
+float ED_wpaint_blend_tool(
+ const int tool,
+ const float weight,
+ const float paintval, const float alpha);
+/* Utility for tools to ensure vertex groups exist before they begin. */
+enum eWPaintFlag {
+ WPAINT_ENSURE_MIRROR = (1 << 0),
+};
+struct WPaintVGroupIndex {
+ int active;
+ int mirror;
+};
+bool ED_wpaint_ensure_data(
+ struct bContext *C, struct ReportList *reports,
+ enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index);
+int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, const int vgroup_active);
+
+/* paint_vertex_color_ops.c */
+void PAINT_OT_vertex_color_set(struct wmOperatorType *ot);
+void PAINT_OT_vertex_color_from_weight(struct wmOperatorType *ot);
+void PAINT_OT_vertex_color_smooth(struct wmOperatorType *ot);
+void PAINT_OT_vertex_color_brightness_contrast(struct wmOperatorType *ot);
+void PAINT_OT_vertex_color_hsv(struct wmOperatorType *ot);
+void PAINT_OT_vertex_color_invert(struct wmOperatorType *ot);
+void PAINT_OT_vertex_color_levels(struct wmOperatorType *ot);
+
+/* paint_vertex_weight_ops.c */
+void PAINT_OT_weight_from_bones(struct wmOperatorType *ot);
+void PAINT_OT_weight_sample(struct wmOperatorType *ot);
+void PAINT_OT_weight_sample_group(struct wmOperatorType *ot);
/* paint_vertex_proj.c */
struct VertProjHandle;
@@ -160,7 +188,7 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr);
void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th);
int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy);
void *paint_2d_new_stroke(struct bContext *, struct wmOperator *, int mode);
-void paint_2d_redraw(const bContext *C, void *ps, bool final);
+void paint_2d_redraw(const struct bContext *C, void *ps, bool final);
void paint_2d_stroke_done(void *ps);
void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size);
void paint_2d_bucket_fill(const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps);
@@ -214,10 +242,10 @@ void paint_calc_redraw_planes(float planes[4][4],
const struct rcti *screen_rect);
float paint_calc_object_space_radius(struct ViewContext *vc, const float center[3], float pixel_radius);
-float paint_get_tex_pixel(struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread);
-void paint_get_tex_pixel_col(struct MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert, struct ColorSpace *colorspace);
+float paint_get_tex_pixel(const struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread);
+void paint_get_tex_pixel_col(const struct MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert, struct ColorSpace *colorspace);
-void paint_sample_color(bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette);
+void paint_sample_color(struct bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette);
void paint_stroke_operator_properties(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index f88b64129e7..2899cfeedcf 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -256,300 +256,6 @@ static void PALETTE_OT_color_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
-
-static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Scene *scene = CTX_data_scene(C);
- Object *obact = CTX_data_active_object(C);
- unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint);
-
- if (ED_vpaint_fill(obact, paintcol)) {
- ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static void PAINT_OT_vertex_color_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Vertex Colors";
- ot->idname = "PAINT_OT_vertex_color_set";
- ot->description = "Fill the active vertex color layer with the current paint color";
-
- /* api callbacks */
- ot->exec = vertex_color_set_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obact = CTX_data_active_object(C);
- if (ED_vpaint_smooth(obact)) {
- ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Smooth Vertex Colors";
- ot->idname = "PAINT_OT_vertex_color_smooth";
- ot->description = "Smooth colors across vertices";
-
- /* api callbacks */
- ot->exec = vertex_color_smooth_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- 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);
@@ -558,9 +264,14 @@ static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op))
if (!ob || !brush) return OPERATOR_CANCELLED;
- if (ob->mode & OB_MODE_SCULPT)
- BKE_brush_sculpt_reset(brush);
/* TODO: other modes */
+ if (ob->mode & OB_MODE_SCULPT) {
+ BKE_brush_sculpt_reset(brush);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
return OPERATOR_FINISHED;
}
@@ -821,8 +532,6 @@ static int brush_uv_sculpt_tool_set_exec(bContext *C, wmOperator *op)
static void BRUSH_OT_uv_sculpt_tool_set(wmOperatorType *ot)
{
- /* from rna_scene.c */
- extern EnumPropertyItem uv_sculpt_tool_items[];
/* identifiers */
ot->name = "UV Sculpt Tool Set";
ot->description = "Set the UV sculpt tool";
@@ -836,7 +545,7 @@ static void BRUSH_OT_uv_sculpt_tool_set(wmOperatorType *ot)
ot->flag = 0;
/* props */
- ot->prop = RNA_def_enum(ot->srna, "tool", uv_sculpt_tool_items, 0, "Tool", "");
+ ot->prop = RNA_def_enum(ot->srna, "tool", rna_enum_uv_sculpt_tool_items, 0, "Tool", "");
}
/***** Stencil Control *****/
@@ -1351,6 +1060,7 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_vertex_color_hsv);
WM_operatortype_append(PAINT_OT_vertex_color_invert);
WM_operatortype_append(PAINT_OT_vertex_color_levels);
+ WM_operatortype_append(PAINT_OT_vertex_color_from_weight);
/* face-select */
WM_operatortype_append(PAINT_OT_face_select_linked);
@@ -1615,6 +1325,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
keymap->poll = vertex_paint_mode_poll;
WM_keymap_verify_item(keymap, "PAINT_OT_vertex_paint", LEFTMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "PAINT_OT_brush_colors_flip", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap,
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 05270dbfa09..bb2cd52a41e 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -580,7 +580,10 @@ static float paint_stroke_integrate_overlap(Brush *br, float factor)
max = overlap;
}
- return 1.0f / max;
+ if (max == 0.0f)
+ return 1.0f;
+ else
+ return 1.0f / max;
}
static float paint_space_stroke_spacing_variable(const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length)
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 31c471c3517..7668b8ebd99 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -171,7 +171,7 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3],
return len_v3(delta) / scale;
}
-float paint_get_tex_pixel(MTex *mtex, float u, float v, struct ImagePool *pool, int thread)
+float paint_get_tex_pixel(const MTex *mtex, float u, float v, struct ImagePool *pool, int thread)
{
float intensity, rgba[4];
float co[3] = {u, v, 0.0f};
@@ -182,7 +182,7 @@ float paint_get_tex_pixel(MTex *mtex, float u, float v, struct ImagePool *pool,
return intensity;
}
-void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert_to_linear, struct ColorSpace *colorspace)
+void paint_get_tex_pixel_col(const MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert_to_linear, struct ColorSpace *colorspace)
{
float co[3] = {u, v, 0.0f};
int hasrgb;
@@ -426,7 +426,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
Palette *palette = BKE_paint_palette(paint);
- PaletteColor *color;
+ PaletteColor *color = NULL;
Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
unsigned int col;
const unsigned char *cp;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 991025a4d5d..f8509a3824c 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -27,19 +27,20 @@
/** \file blender/editors/sculpt_paint/paint_vertex.c
* \ingroup edsculpt
+ *
+ * Used for vertex color & weight paint and mode switching.
+ *
+ * \note This file is already big,
+ * use `paint_vertex_color_ops.c` & `paint_vertex_weight_ops.c` for general purpose operators.
*/
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
+#include "BLI_listbase.h"
+#include "BLI_rect.h"
#include "BLI_math.h"
#include "BLI_array_utils.h"
-#include "BLI_bitmap.h"
-#include "BLI_stack.h"
-
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_colormanagement.h"
+#include "BLI_task.h"
#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
@@ -50,39 +51,119 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_action.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
-#include "BKE_modifier.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
#include "BKE_report.h"
-#include "BKE_colortools.h"
+#include "BKE_subsurf.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_armature.h"
#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "bmesh.h"
+#include "BKE_ccg.h"
+
+#include "sculpt_intern.h"
#include "paint_intern.h" /* own include */
-/* small structure to defer applying weight-paint results */
-struct WPaintDefer {
- int index;
- float alpha, weight;
+/* Use for 'blur' brush, align with PBVH nodes, created and freed on each update. */
+struct VPaintAverageAccum {
+ uint len;
+ uint value[3];
+};
+
+struct WPaintAverageAccum {
+ uint len;
+ double value;
+};
+
+struct NormalAnglePrecalc {
+ bool do_mask_normal;
+ /* what angle to mask at */
+ float angle;
+ /* cos(angle), faster to compare */
+ float angle__cos;
+ float angle_inner;
+ float angle_inner__cos;
+ /* difference between angle and angle_inner, for easy access */
+ float angle_range;
};
+
+static void view_angle_limits_init(
+ struct NormalAnglePrecalc *a, float angle, bool do_mask_normal)
+{
+ angle = RAD2DEGF(angle);
+ a->do_mask_normal = do_mask_normal;
+ if (do_mask_normal) {
+ a->angle_inner = angle;
+ a->angle = (a->angle_inner + 90.0f) * 0.5f;
+ }
+ else {
+ a->angle_inner = a->angle = angle;
+ }
+
+ a->angle_inner *= (float)(M_PI_2 / 90);
+ a->angle *= (float)(M_PI_2 / 90);
+ a->angle_range = a->angle - a->angle_inner;
+
+ if (a->angle_range <= 0.0f) {
+ a->do_mask_normal = false; /* no need to do blending */
+ }
+
+ a->angle__cos = cosf(a->angle);
+ a->angle_inner__cos = cosf(a->angle_inner);
+}
+
+static float view_angle_limits_apply_falloff(
+ const struct NormalAnglePrecalc *a, float angle_cos, float *mask_p)
+{
+ if (angle_cos <= a->angle__cos) {
+ /* outsize the normal limit */
+ return false;
+ }
+ else if (angle_cos < a->angle_inner__cos) {
+ *mask_p *= (a->angle - acosf(angle_cos)) / a->angle_range;
+ return true;
+ }
+ else {
+ return true;
+ }
+}
+
+static bool vwpaint_use_normal(const VPaint *vp)
+{
+ return ((vp->paint.brush->flag & BRUSH_FRONTFACE) != 0) ||
+ ((vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
+}
+
+static bool brush_use_accumulate(const Brush *brush)
+{
+ return (brush->flag & BRUSH_ACCUMULATE) != 0 || brush->vertexpaint_tool == PAINT_BLEND_SMEAR;
+}
+
+static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev, MDeformVert *dvert_curr, int index)
+{
+ MDeformVert *dv_curr = &dvert_curr[index];
+ MDeformVert *dv_prev = &dvert_prev[index];
+ if (dv_prev->flag == 1) {
+ dv_prev->flag = 0;
+ defvert_copy(dv_prev, dv_curr);
+ }
+ return dv_prev;
+}
+
/* check if we can do partial updates and have them draw realtime
* (without rebuilding the 'derivedFinal') */
static bool vertex_paint_use_fast_update_check(Object *ob)
@@ -124,7 +205,7 @@ int vertex_paint_mode_poll(bContext *C)
int vertex_paint_poll(bContext *C)
{
- if (vertex_paint_mode_poll(C) &&
+ if (vertex_paint_mode_poll(C) &&
BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint))
{
ScrArea *sa = CTX_wm_area(C);
@@ -163,639 +244,47 @@ int weight_paint_poll(bContext *C)
return 0;
}
-static VPaint *new_vpaint(int wpaint)
+static VPaint *new_vpaint(void)
{
VPaint *vp = MEM_callocN(sizeof(VPaint), "VPaint");
-
- vp->flag = (wpaint) ? 0 : VP_SPRAY;
+
vp->paint.flags |= PAINT_SHOW_BRUSH;
return vp;
}
-static int *get_indexarray(Mesh *me)
-{
- return MEM_mallocN(sizeof(int) * (me->totpoly + 1), "vertexpaint");
-}
-
-unsigned int vpaint_get_current_col(Scene *scene, VPaint *vp)
+uint vpaint_get_current_col(Scene *scene, VPaint *vp)
{
Brush *brush = BKE_paint_brush(&vp->paint);
- unsigned char col[4];
+ uchar col[4];
rgb_float_to_uchar(col, BKE_brush_color_get(scene, brush));
col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */
- return *(unsigned int *)col;
-}
-
-static void do_shared_vertexcol(Mesh *me, bool *mlooptag)
-{
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- MPoly *mp;
- int (*scol)[4];
- int i, j;
- bool has_shared = false;
-
- /* if no mloopcol: do not do */
- /* if mtexpoly: only the involved faces, otherwise all */
-
- if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return;
-
- scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol");
-
- for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
- if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
- MLoop *ml = me->mloop + mp->loopstart;
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
- for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
- scol[ml->v][0] += lcol->r;
- scol[ml->v][1] += lcol->g;
- scol[ml->v][2] += lcol->b;
- scol[ml->v][3] += 1;
- has_shared = 1;
- }
- }
- }
-
- if (has_shared) {
- for (i = 0; i < me->totvert; i++) {
- if (scol[i][3] != 0) {
- scol[i][0] = divide_round_i(scol[i][0], scol[i][3]);
- scol[i][1] = divide_round_i(scol[i][1], scol[i][3]);
- scol[i][2] = divide_round_i(scol[i][2], scol[i][3]);
- }
- }
-
- for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
- if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
- MLoop *ml = me->mloop + mp->loopstart;
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
- for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
- if (mlooptag[mp->loopstart + j]) {
- lcol->r = scol[ml->v][0];
- lcol->g = scol[ml->v][1];
- lcol->b = scol[ml->v][2];
- }
- }
- }
- }
- }
-
- MEM_freeN(scol);
-}
-
-static bool make_vertexcol(Object *ob) /* single ob */
-{
- Mesh *me;
-
- if (ID_IS_LINKED_DATABLOCK(ob) ||
- ((me = BKE_mesh_from_object(ob)) == NULL) ||
- (me->totpoly == 0) ||
- (me->edit_btmesh))
- {
- return false;
- }
-
- /* copies from shadedisplist to mcol */
- if (!me->mloopcol && me->totloop) {
- CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
- BKE_mesh_update_customdata_pointers(me, true);
- }
-
- DAG_id_tag_update(&me->id, 0);
-
- return (me->mloopcol != NULL);
-}
-
-/* mirror_vgroup is set to -1 when invalid */
-static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
-{
- bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active);
-
- if (defgroup) {
- int mirrdef;
- char name_flip[MAXBONENAME];
-
- BKE_deform_flip_side_name(name_flip, defgroup->name, false);
- mirrdef = defgroup_name_index(ob, name_flip);
- if (mirrdef == -1) {
- if (BKE_defgroup_new(ob, name_flip)) {
- mirrdef = BLI_listbase_count(&ob->defbase) - 1;
- }
- }
-
- /* curdef should never be NULL unless this is
- * a lamp and BKE_object_defgroup_add_name fails */
- return mirrdef;
- }
-
- return -1;
-}
-
-static void free_vpaint_prev(VPaint *vp)
-{
- if (vp->vpaint_prev) {
- MEM_freeN(vp->vpaint_prev);
- vp->vpaint_prev = NULL;
- vp->tot = 0;
- }
-}
-
-static void free_wpaint_prev(VPaint *vp)
-{
- if (vp->wpaint_prev) {
- BKE_defvert_array_free(vp->wpaint_prev, vp->tot);
- vp->wpaint_prev = NULL;
- vp->tot = 0;
- }
-}
-
-static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot)
-{
- free_vpaint_prev(vp);
-
- vp->tot = tot;
-
- if (lcol == NULL || tot == 0) return;
-
- vp->vpaint_prev = MEM_mallocN(sizeof(int) * tot, "vpaint_prev");
- memcpy(vp->vpaint_prev, lcol, sizeof(int) * tot);
-
-}
-
-static void copy_wpaint_prev(VPaint *wp, MDeformVert *dverts, int dcount)
-{
- free_wpaint_prev(wp);
-
- if (dverts && dcount) {
-
- wp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev");
- wp->tot = dcount;
- BKE_defvert_array_copy(wp->wpaint_prev, dverts, dcount);
- }
-}
-
-bool ED_vpaint_fill(Object *ob, unsigned int paintcol)
-{
- Mesh *me;
- MPoly *mp;
- int i, j;
- bool selected;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL) ||
- (me->mloopcol == NULL && (make_vertexcol(ob) == false)))
- {
- return false;
- }
-
- selected = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
-
- mp = me->mpoly;
- for (i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
-
- if (selected && !(mp->flag & ME_FACE_SEL))
- continue;
-
- for (j = 0; j < mp->totloop; j++, lcol++) {
- *(int *)lcol = paintcol;
- }
- }
-
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
-
- DAG_id_tag_update(&me->id, 0);
-
- return true;
-}
-
-
-/* fills in the selected faces with the current weight and vertex group */
-bool ED_wpaint_fill(VPaint *wp, Object *ob, float paintweight)
-{
- Mesh *me = ob->data;
- MPoly *mp;
- MDeformWeight *dw, *dw_prev;
- int vgroup_active, vgroup_mirror = -1;
- unsigned int index;
- const bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
-
- /* mutually exclusive, could be made into a */
- const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(me);
-
- if (me->totpoly == 0 || me->dvert == NULL || !me->mpoly) {
- return false;
- }
-
- vgroup_active = ob->actdef - 1;
-
- /* if mirror painting, find the other group */
- if (me->editflag & ME_EDIT_MIRROR_X) {
- vgroup_mirror = wpaint_mirror_vgroup_ensure(ob, vgroup_active);
- }
-
- copy_wpaint_prev(wp, me->dvert, me->totvert);
-
- for (index = 0, mp = me->mpoly; index < me->totpoly; index++, mp++) {
- unsigned int fidx = mp->totloop - 1;
-
- if ((paint_selmode == SCE_SELECT_FACE) && !(mp->flag & ME_FACE_SEL)) {
- continue;
- }
-
- do {
- unsigned int vidx = me->mloop[mp->loopstart + fidx].v;
-
- if (!me->dvert[vidx].flag) {
- if ((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) {
- continue;
- }
-
- dw = defvert_verify_index(&me->dvert[vidx], vgroup_active);
- if (dw) {
- dw_prev = defvert_verify_index(wp->wpaint_prev + vidx, vgroup_active);
- dw_prev->weight = dw->weight; /* set the undo weight */
- dw->weight = paintweight;
-
- if (me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
- int j = mesh_get_x_mirror_vert(ob, NULL, vidx, topology);
- if (j >= 0) {
- /* copy, not paint again */
- if (vgroup_mirror != -1) {
- dw = defvert_verify_index(me->dvert + j, vgroup_mirror);
- dw_prev = defvert_verify_index(wp->wpaint_prev + j, vgroup_mirror);
- }
- else {
- dw = defvert_verify_index(me->dvert + j, vgroup_active);
- dw_prev = defvert_verify_index(wp->wpaint_prev + j, vgroup_active);
- }
- dw_prev->weight = dw->weight; /* set the undo weight */
- dw->weight = paintweight;
- }
- }
- }
- me->dvert[vidx].flag = 1;
- }
-
- } while (fidx--);
- }
-
- {
- MDeformVert *dv = me->dvert;
- for (index = me->totvert; index != 0; index--, dv++) {
- dv->flag = 0;
- }
- }
-
- copy_wpaint_prev(wp, NULL, 0);
-
- DAG_id_tag_update(&me->id, 0);
-
- return true;
-}
-
-bool ED_vpaint_smooth(Object *ob)
-{
- Mesh *me;
- MPoly *mp;
-
- int i, j;
-
- bool *mlooptag;
- bool selected;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL) ||
- (me->mloopcol == NULL && (make_vertexcol(ob) == false)))
- {
- return false;
- }
-
- selected = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
-
- mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
-
- /* simply tag loops of selected faces */
- mp = me->mpoly;
- for (i = 0; i < me->totpoly; i++, mp++) {
- MLoop *ml = me->mloop + mp->loopstart;
- int ml_index = mp->loopstart;
-
- if (selected && !(mp->flag & ME_FACE_SEL))
- continue;
-
- for (j = 0; j < mp->totloop; j++, ml_index++, ml++) {
- mlooptag[ml_index] = true;
- }
- }
-
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
-
- do_shared_vertexcol(me, mlooptag);
-
- MEM_freeN(mlooptag);
-
- DAG_id_tag_update(&me->id, 0);
-
- 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)
-{
- VPaint *vp = scene->toolsettings->vpaint;
- Mesh *me;
- Object *ob;
- float igam, fac;
- int a, temp;
- unsigned char *cp, gamtab[256];
-
- ob = OBACT;
- me = BKE_mesh_from_object(ob);
-
- if (!(ob->mode & OB_MODE_VERTEX_PAINT)) return;
- if (me == 0 || me->mcol == 0 || me->totface == 0) return;
-
- igam = 1.0 / vp->gamma;
- for (a = 0; a < 256; a++) {
-
- fac = ((float)a) / 255.0;
- fac = vp->mul * pow(fac, igam);
-
- temp = 255.9 * fac;
-
- if (temp <= 0) gamtab[a] = 0;
- else if (temp >= 255) gamtab[a] = 255;
- else gamtab[a] = temp;
- }
-
- a = 4 * me->totface;
- cp = (unsigned char *)me->mcol;
- while (a--) {
-
- cp[1] = gamtab[cp[1]];
- cp[2] = gamtab[cp[2]];
- cp[3] = gamtab[cp[3]];
-
- cp += 4;
- }
-}
-#endif
-
-BLI_INLINE unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac)
-{
- unsigned char *cp1, *cp2, *cp;
- int mfac;
- unsigned int col = 0;
-
- if (fac == 0) {
- return col1;
- }
-
- if (fac >= 255) {
- return col2;
- }
-
- mfac = 255 - fac;
-
- cp1 = (unsigned char *)&col1;
- cp2 = (unsigned char *)&col2;
- cp = (unsigned char *)&col;
-
- cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255);
- cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255);
- cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255);
- cp[3] = 255;
-
- return col;
-}
-
-BLI_INLINE unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac)
-{
- unsigned char *cp1, *cp2, *cp;
- int temp;
- unsigned int col = 0;
-
- if (fac == 0) {
- return col1;
- }
-
- cp1 = (unsigned char *)&col1;
- cp2 = (unsigned char *)&col2;
- cp = (unsigned char *)&col;
-
- temp = cp1[0] + divide_round_i((fac * cp2[0]), 255);
- cp[0] = (temp > 254) ? 255 : temp;
- temp = cp1[1] + divide_round_i((fac * cp2[1]), 255);
- cp[1] = (temp > 254) ? 255 : temp;
- temp = cp1[2] + divide_round_i((fac * cp2[2]), 255);
- cp[2] = (temp > 254) ? 255 : temp;
- cp[3] = 255;
-
- return col;
-}
-
-BLI_INLINE unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac)
-{
- unsigned char *cp1, *cp2, *cp;
- int temp;
- unsigned int col = 0;
-
- if (fac == 0) {
- return col1;
- }
-
- cp1 = (unsigned char *)&col1;
- cp2 = (unsigned char *)&col2;
- cp = (unsigned char *)&col;
-
- temp = cp1[0] - divide_round_i((fac * cp2[0]), 255);
- cp[0] = (temp < 0) ? 0 : temp;
- temp = cp1[1] - divide_round_i((fac * cp2[1]), 255);
- cp[1] = (temp < 0) ? 0 : temp;
- temp = cp1[2] - divide_round_i((fac * cp2[2]), 255);
- cp[2] = (temp < 0) ? 0 : temp;
- cp[3] = 255;
-
- return col;
-}
-
-BLI_INLINE unsigned int mcol_mul(unsigned int col1, unsigned int col2, int fac)
-{
- unsigned char *cp1, *cp2, *cp;
- int mfac;
- unsigned int col = 0;
-
- if (fac == 0) {
- return col1;
- }
-
- mfac = 255 - fac;
-
- cp1 = (unsigned char *)&col1;
- cp2 = (unsigned char *)&col2;
- cp = (unsigned char *)&col;
-
- /* first mul, then blend the fac */
- cp[0] = divide_round_i(mfac * cp1[0] * 255 + fac * cp2[0] * cp1[0], 255 * 255);
- cp[1] = divide_round_i(mfac * cp1[1] * 255 + fac * cp2[1] * cp1[1], 255 * 255);
- cp[2] = divide_round_i(mfac * cp1[2] * 255 + fac * cp2[2] * cp1[2], 255 * 255);
- cp[3] = 255;
-
- return col;
-}
-
-BLI_INLINE unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac)
-{
- unsigned char *cp1, *cp2, *cp;
- int mfac;
- unsigned int col = 0;
-
- if (fac == 0) {
- return col1;
- }
- else if (fac >= 255) {
- return col2;
- }
-
- mfac = 255 - fac;
-
- cp1 = (unsigned char *)&col1;
- cp2 = (unsigned char *)&col2;
- cp = (unsigned char *)&col;
-
- /* See if are lighter, if so mix, else don't do anything.
- * if the paint col is darker then the original, then ignore */
- if (IMB_colormanagement_get_luminance_byte(cp1) > IMB_colormanagement_get_luminance_byte(cp2)) {
- return col1;
- }
-
- cp[0] = divide_round_i(mfac * cp1[0] + fac * cp2[0], 255);
- cp[1] = divide_round_i(mfac * cp1[1] + fac * cp2[1], 255);
- cp[2] = divide_round_i(mfac * cp1[2] + fac * cp2[2], 255);
- cp[3] = 255;
-
- return col;
-}
-
-BLI_INLINE unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac)
-{
- unsigned char *cp1, *cp2, *cp;
- int mfac;
- unsigned int col = 0;
-
- if (fac == 0) {
- return col1;
- }
- else if (fac >= 255) {
- return col2;
- }
-
- mfac = 255 - fac;
-
- cp1 = (unsigned char *)&col1;
- cp2 = (unsigned char *)&col2;
- cp = (unsigned char *)&col;
-
- /* See if were darker, if so mix, else don't do anything.
- * if the paint col is brighter then the original, then ignore */
- if (IMB_colormanagement_get_luminance_byte(cp1) < IMB_colormanagement_get_luminance_byte(cp2)) {
- return col1;
- }
-
- cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255);
- cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255);
- cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255);
- cp[3] = 255;
- return col;
-}
-
-/* wpaint has 'wpaint_blend_tool' */
-static unsigned int vpaint_blend_tool(const int tool, const unsigned int col,
- const unsigned int paintcol, const int alpha_i)
-{
- switch (tool) {
- case PAINT_BLEND_MIX:
- case PAINT_BLEND_BLUR: return mcol_blend(col, paintcol, alpha_i);
- case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i);
- case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i);
- case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i);
- case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i);
- case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i);
- default:
- BLI_assert(0);
- return 0;
- }
+ return *(uint *)col;
}
/* wpaint has 'wpaint_blend' */
-static unsigned int vpaint_blend(VPaint *vp, unsigned int col, unsigned int colorig, const
- unsigned int paintcol, const int alpha_i,
- /* pre scaled from [0-1] --> [0-255] */
- const int brush_alpha_value_i)
+static uint vpaint_blend(
+ const VPaint *vp, uint color_curr, uint color_orig,
+ uint color_paint, const int alpha_i,
+ /* pre scaled from [0-1] --> [0-255] */
+ const int brush_alpha_value_i)
{
- Brush *brush = BKE_paint_brush(&vp->paint);
+ const Brush *brush = vp->paint.brush;
const int tool = brush->vertexpaint_tool;
- col = vpaint_blend_tool(tool, col, paintcol, alpha_i);
+ uint color_blend = ED_vpaint_blend_tool(tool, color_curr, color_paint, alpha_i);
- /* if no spray, clip color adding with colorig & orig alpha */
- if ((vp->flag & VP_SPRAY) == 0) {
- unsigned int testcol, a;
+ /* if no accumulate, clip color adding with colorig & orig alpha */
+ if (!brush_use_accumulate(brush)) {
+ uint color_test, a;
char *cp, *ct, *co;
-
- testcol = vpaint_blend_tool(tool, colorig, paintcol, brush_alpha_value_i);
-
- cp = (char *)&col;
- ct = (char *)&testcol;
- co = (char *)&colorig;
-
+
+ color_test = ED_vpaint_blend_tool(tool, color_orig, color_paint, brush_alpha_value_i);
+
+ cp = (char *)&color_blend;
+ ct = (char *)&color_test;
+ co = (char *)&color_orig;
+
for (a = 0; a < 4; a++) {
if (ct[a] < co[a]) {
if (cp[a] < ct[a]) cp[a] = ct[a];
@@ -808,176 +297,51 @@ static unsigned int vpaint_blend(VPaint *vp, unsigned int col, unsigned int colo
}
}
- return col;
-}
-
-
-static int sample_backbuf_area(ViewContext *vc, int *indexar, int totpoly, int x, int y, float size)
-{
- struct ImBuf *ibuf;
- int a, tot = 0, index;
-
- /* brecht: disabled this because it obviously fails for
- * brushes with size > 64, why is this here? */
- /*if (size > 64.0) size = 64.0;*/
-
- ibuf = ED_view3d_backbuf_read(vc, x - size, y - size, x + size, y + size);
- if (ibuf) {
- unsigned int *rt = ibuf->rect;
-
- memset(indexar, 0, sizeof(int) * (totpoly + 1));
-
- size = ibuf->x * ibuf->y;
- while (size--) {
-
- if (*rt) {
- index = *rt;
- if (index > 0 && index <= totpoly) {
- indexar[index] = 1;
- }
- }
-
- rt++;
- }
-
- for (a = 1; a <= totpoly; a++) {
- if (indexar[a]) {
- indexar[tot++] = a;
- }
- }
-
- IMB_freeImBuf(ibuf);
- }
-
- return tot;
-}
-
-/* whats _dl mean? */
-static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co[3],
- const float mval[2], const float brush_size_pressure, float rgba[4])
-{
- float co_ss[2]; /* screenspace */
-
- if (ED_view3d_project_float_object(vc->ar,
- co, co_ss,
- V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ if ((brush->flag & BRUSH_LOCK_ALPHA) &&
+ !ELEM(tool, PAINT_BLEND_ALPHA_SUB, PAINT_BLEND_ALPHA_ADD))
{
- const float dist_sq = len_squared_v2v2(mval, co_ss);
-
- if (dist_sq <= SQUARE(brush_size_pressure)) {
- Brush *brush = BKE_paint_brush(&vp->paint);
- const float dist = sqrtf(dist_sq);
- float factor;
-
- if (brush->mtex.tex && rgba) {
- if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
- BKE_brush_sample_tex_3D(vc->scene, brush, co, rgba, 0, NULL);
- }
- else {
- const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
- BKE_brush_sample_tex_3D(vc->scene, brush, co_ss_3d, rgba, 0, NULL);
- }
- factor = rgba[3];
- }
- else {
- factor = 1.0f;
- }
- return factor * BKE_brush_curve_strength_clamped(brush, dist, brush_size_pressure);
- }
+ char *cp, *cc;
+ cp = (char *)&color_blend;
+ cc = (char *)&color_curr;
+ cp[3] = cc[3];
}
- if (rgba)
- zero_v4(rgba);
- return 0.0f;
-}
-
-static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc,
- float vpimat[3][3], const DMCoNo *v_co_no,
- const float mval[2],
- const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4])
-{
- float strength = calc_vp_strength_col_dl(vp, vc, v_co_no->co, mval, brush_size_pressure, rgba);
-
- if (strength > 0.0f) {
- float alpha = brush_alpha_pressure * strength;
- if (vp->flag & VP_NORMALS) {
- float dvec[3];
-
- /* transpose ! */
- dvec[2] = dot_v3v3(vpimat[2], v_co_no->no);
- if (dvec[2] > 0.0f) {
- dvec[0] = dot_v3v3(vpimat[0], v_co_no->no);
- dvec[1] = dot_v3v3(vpimat[1], v_co_no->no);
-
- alpha *= dvec[2] / len_v3(dvec);
- }
- else {
- return 0.0f;
- }
- }
-
- return alpha;
- }
-
- return 0.0f;
-}
-
-
-BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha)
-{
- const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */
- return (paintval * talpha) + (weight * (1.0f - talpha));
-}
-BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha)
-{
- return weight + (paintval * alpha);
-}
-BLI_INLINE float wval_sub(const float weight, const float paintval, const float alpha)
-{
- return weight - (paintval * alpha);
-}
-BLI_INLINE float wval_mul(const float weight, const float paintval, const float alpha)
-{ /* first mul, then blend the fac */
- return ((1.0f - alpha) + (alpha * paintval)) * weight;
+ return color_blend;
}
-BLI_INLINE float wval_lighten(const float weight, const float paintval, const float alpha)
-{
- return (weight < paintval) ? wval_blend(weight, paintval, alpha) : weight;
-}
-BLI_INLINE float wval_darken(const float weight, const float paintval, const float alpha)
-{
- return (weight > paintval) ? wval_blend(weight, paintval, alpha) : weight;
-}
-
-/* vpaint has 'vpaint_blend_tool' */
-/* result is not clamped from [0-1] */
-static float wpaint_blend_tool(const int tool,
- /* dw->weight */
- const float weight,
- const float paintval, const float alpha)
+static void tex_color_alpha(
+ VPaint *vp, const ViewContext *vc, const float co[3],
+ float r_rgba[4])
{
- switch (tool) {
- case PAINT_BLEND_MIX:
- case PAINT_BLEND_BLUR: return wval_blend(weight, paintval, alpha);
- case PAINT_BLEND_ADD: return wval_add(weight, paintval, alpha);
- case PAINT_BLEND_SUB: return wval_sub(weight, paintval, alpha);
- case PAINT_BLEND_MUL: return wval_mul(weight, paintval, alpha);
- case PAINT_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha);
- case PAINT_BLEND_DARKEN: return wval_darken(weight, paintval, alpha);
- default:
- BLI_assert(0);
- return 0.0f;
+ const Brush *brush = BKE_paint_brush(&vp->paint);
+ BLI_assert(brush->mtex.tex != NULL);
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
+ BKE_brush_sample_tex_3D(vc->scene, brush, co, r_rgba, 0, NULL);
+ }
+ else {
+ float co_ss[2]; /* screenspace */
+ if (ED_view3d_project_float_object(
+ vc->ar,
+ co, co_ss,
+ V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ {
+ const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
+ BKE_brush_sample_tex_3D(vc->scene, brush, co_ss_3d, r_rgba, 0, NULL);
+ }
+ else {
+ zero_v4(r_rgba);
+ }
}
}
/* vpaint has 'vpaint_blend' */
-static float wpaint_blend(VPaint *wp, float weight, float weight_prev,
- const float alpha, float paintval,
- const float brush_alpha_value,
- const short do_flip)
+static float wpaint_blend(
+ const VPaint *wp, float weight,
+ const float alpha, float paintval,
+ const float UNUSED(brush_alpha_value),
+ const short do_flip)
{
- Brush *brush = BKE_paint_brush(&wp->paint);
+ const Brush *brush = wp->paint.brush;
int tool = brush->vertexpaint_tool;
if (do_flip) {
@@ -994,257 +358,30 @@ static float wpaint_blend(VPaint *wp, float weight, float weight_prev,
tool = PAINT_BLEND_LIGHTEN; break;
}
}
-
- weight = wpaint_blend_tool(tool, weight, paintval, alpha);
- CLAMP(weight, 0.0f, 1.0f);
-
- /* if no spray, clip result with orig weight & orig alpha */
- if ((wp->flag & VP_SPRAY) == 0) {
- float testw = wpaint_blend_tool(tool, weight_prev, paintval, brush_alpha_value);
+ weight = ED_wpaint_blend_tool(tool, weight, paintval, alpha);
- CLAMP(testw, 0.0f, 1.0f);
- if (testw < weight_prev) {
- if (weight < testw) weight = testw;
- else if (weight > weight_prev) weight = weight_prev;
- }
- else {
- if (weight > testw) weight = testw;
- else if (weight < weight_prev) weight = weight_prev;
- }
- }
+ CLAMP(weight, 0.0f, 1.0f);
return weight;
}
-/* ----------------------------------------------------- */
-
-
-/* sets wp->weight to the closest weight value to vertex */
-/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
-static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ViewContext vc;
- Mesh *me;
- bool changed = false;
-
- view3d_set_viewcontext(C, &vc);
- me = BKE_mesh_from_object(vc.obact);
-
- if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) {
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- int v_idx_best = -1;
- unsigned int index;
-
- view3d_operator_needs_opengl(C);
- ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
-
- if (use_vert_sel) {
- if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) {
- v_idx_best = index;
- }
- }
- else {
- if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
- v_idx_best = index;
- }
- else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
- /* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */
- BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
- }
- }
-
- if (v_idx_best != -1) { /* should always be valid */
- ToolSettings *ts = vc.scene->toolsettings;
- Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
- const int vgroup_active = vc.obact->actdef - 1;
- float vgroup_weight = defvert_find_weight(&me->dvert[v_idx_best], vgroup_active);
-
- /* use combined weight in multipaint mode, since that's what is displayed to the user in the colors */
- if (ts->multipaint) {
- int defbase_tot_sel;
- const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
- bool *defbase_sel = BKE_object_defgroup_selected_get(vc.obact, defbase_tot, &defbase_tot_sel);
-
- if (defbase_tot_sel > 1) {
- if (me->editflag & ME_EDIT_MIRROR_X) {
- BKE_object_defgroup_mirror_selection(
- vc.obact, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
- }
-
- vgroup_weight = BKE_defvert_multipaint_collective_weight(
- &me->dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, ts->auto_normalize);
-
- /* if autonormalize is enabled, but weights are not normalized, the value can exceed 1 */
- CLAMP(vgroup_weight, 0.0f, 1.0f);
- }
-
- MEM_freeN(defbase_sel);
- }
-
- BKE_brush_weight_set(vc.scene, brush, vgroup_weight);
- changed = true;
- }
- }
-
- if (changed) {
- /* not really correct since the brush didnt change, but redraws the toolbar */
- WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); /* ts->wpaint->paint.brush */
-
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-void PAINT_OT_weight_sample(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Weight Paint Sample Weight";
- ot->idname = "PAINT_OT_weight_sample";
- ot->description = "Use the mouse to sample a weight in the 3D view";
-
- /* api callbacks */
- ot->invoke = weight_sample_invoke;
- ot->poll = weight_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-}
-
-/* samples cursor location, and gives menu with vertex groups to activate */
-static bool weight_paint_sample_enum_itemf__helper(const MDeformVert *dvert, const int defbase_tot, int *groups)
-{
- /* this func fills in used vgroup's */
- bool found = false;
- int i = dvert->totweight;
- MDeformWeight *dw;
- for (dw = dvert->dw; i > 0; dw++, i--) {
- if (dw->def_nr < defbase_tot) {
- groups[dw->def_nr] = true;
- found = true;
- }
- }
- return found;
-}
-static EnumPropertyItem *weight_paint_sample_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- if (C) {
- wmWindow *win = CTX_wm_window(C);
- if (win && win->eventstate) {
- ViewContext vc;
- Mesh *me;
-
- view3d_set_viewcontext(C, &vc);
- me = BKE_mesh_from_object(vc.obact);
-
- if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
- const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups");
- bool found = false;
- unsigned int index;
-
- const int mval[2] = {
- win->eventstate->x - vc.ar->winrct.xmin,
- win->eventstate->y - vc.ar->winrct.ymin,
- };
-
- view3d_operator_needs_opengl(C);
- ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
-
- if (use_vert_sel) {
- if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) {
- MDeformVert *dvert = &me->dvert[index];
- found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
- }
- }
- else {
- if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
- MPoly *mp = &me->mpoly[index];
- unsigned int fidx = mp->totloop - 1;
-
- do {
- MDeformVert *dvert = &me->dvert[me->mloop[mp->loopstart + fidx].v];
- found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
- } while (fidx--);
- }
- }
-
- if (found == false) {
- MEM_freeN(groups);
- }
- else {
- EnumPropertyItem *item = NULL, item_tmp = {0};
- int totitem = 0;
- int i = 0;
- bDeformGroup *dg;
- for (dg = vc.obact->defbase.first; dg && i < defbase_tot; i++, dg = dg->next) {
- if (groups[i]) {
- item_tmp.identifier = item_tmp.name = dg->name;
- item_tmp.value = i;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- MEM_freeN(groups);
- return item;
- }
- }
- }
- }
-
- return DummyRNA_NULL_items;
-}
-
-static int weight_sample_group_exec(bContext *C, wmOperator *op)
+static float wpaint_clamp_monotonic(float oldval, float curval, float newval)
{
- int type = RNA_enum_get(op->ptr, "group");
- ViewContext vc;
- view3d_set_viewcontext(C, &vc);
-
- BLI_assert(type + 1 >= 0);
- vc.obact->actdef = type + 1;
-
- DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact);
- return OPERATOR_FINISHED;
+ if (newval < oldval)
+ return MIN2(newval, curval);
+ else if (newval > oldval)
+ return MAX2(newval, curval);
+ else
+ return newval;
}
-/* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather than its own operator */
-void PAINT_OT_weight_sample_group(wmOperatorType *ot)
-{
- PropertyRNA *prop = NULL;
-
- /* identifiers */
- ot->name = "Weight Paint Sample Group";
- ot->idname = "PAINT_OT_weight_sample_group";
- ot->description = "Select one of the vertex groups available under current mouse position";
-
- /* api callbacks */
- ot->exec = weight_sample_group_exec;
- ot->invoke = WM_menu_invoke;
- ot->poll = weight_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* keyingset to use (dynamic enum) */
- prop = RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
- RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- ot->prop = prop;
-}
+/* ----------------------------------------------------- */
static void do_weight_paint_normalize_all(MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap)
{
float sum = 0.0f, fac;
- unsigned int i, tot = 0;
+ uint i, tot = 0;
MDeformWeight *dw;
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
@@ -1290,7 +427,7 @@ static bool do_weight_paint_normalize_all_locked(
float sum = 0.0f, fac;
float sum_unlock = 0.0f;
float lock_weight = 0.0f;
- unsigned int i, tot = 0;
+ uint i, tot = 0;
MDeformWeight *dw;
if (lock_flags == NULL) {
@@ -1390,8 +527,9 @@ static void do_weight_paint_normalize_all_locked_try_active(
}
#if 0 /* UNUSED */
-static bool has_unselected_unlocked_bone_group(int defbase_tot, bool *defbase_sel, int selected,
- const bool *lock_flags, const bool *vgroup_validmap)
+static bool has_unselected_unlocked_bone_group(
+ int defbase_tot, bool *defbase_sel, int selected,
+ const bool *lock_flags, const bool *vgroup_validmap)
{
int i;
if (defbase_tot == selected) {
@@ -1475,7 +613,7 @@ static void multipaint_apply_change(MDeformVert *dvert, const int defbase_tot, f
* Variables stored both for 'active' and 'mirror' sides.
*/
struct WeightPaintGroupData {
- /** index of active group or its mirror
+ /** index of active group or its mirror
*
* - 'active' is always `ob->actdef`.
* - 'mirror' is -1 when 'ME_EDIT_MIRROR_X' flag id disabled,
@@ -1504,13 +642,15 @@ typedef struct WeightPaintInfo {
struct WeightPaintGroupData active, mirror;
- const bool *lock_flags; /* boolean array for locked bones,
- * length of defbase_tot */
- const bool *defbase_sel; /* boolean array for selected bones,
- * length of defbase_tot, cant be const because of how its passed */
-
- const bool *vgroup_validmap; /* same as WeightPaintData.vgroup_validmap,
- * only added here for convenience */
+ /* boolean array for locked bones,
+ * length of defbase_tot */
+ const bool *lock_flags;
+ /* boolean array for selected bones,
+ * length of defbase_tot, cant be const because of how its passed */
+ const bool *defbase_sel;
+ /* same as WeightPaintData.vgroup_validmap,
+ * only added here for convenience */
+ const bool *vgroup_validmap;
bool do_flip;
bool do_multipaint;
@@ -1521,16 +661,16 @@ typedef struct WeightPaintInfo {
static void do_weight_paint_vertex_single(
/* vars which remain the same for every vert */
- VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
+ const VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
/* vars which change on each stroke */
- const unsigned int index, float alpha, float paintweight
- )
+ const uint index, float alpha, float paintweight)
{
Mesh *me = ob->data;
MDeformVert *dv = &me->dvert[index];
bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
-
- MDeformWeight *dw, *dw_prev;
+
+ MDeformWeight *dw;
+ float weight_prev;
/* mirror vars */
int index_mirr;
@@ -1539,20 +679,6 @@ static void do_weight_paint_vertex_single(
MDeformVert *dv_mirr;
MDeformWeight *dw_mirr;
- if (wp->flag & VP_ONLYVGROUP) {
- dw = defvert_find_index(dv, wpi->active.index);
- dw_prev = defvert_find_index(wp->wpaint_prev + index, wpi->active.index);
- }
- else {
- dw = defvert_verify_index(dv, wpi->active.index);
- dw_prev = defvert_verify_index(wp->wpaint_prev + index, wpi->active.index);
- }
-
- if (dw == NULL || dw_prev == NULL) {
- return;
- }
-
-
/* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */
if (me->editflag & ME_EDIT_MIRROR_X) {
index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, topology);
@@ -1568,11 +694,21 @@ static void do_weight_paint_vertex_single(
index_mirr = vgroup_mirr = -1;
}
+ if (wp->flag & VP_FLAG_VGROUP_RESTRICT) {
+ dw = defvert_find_index(dv, wpi->active.index);
+ }
+ else {
+ dw = defvert_verify_index(dv, wpi->active.index);
+ }
+
+ if (dw == NULL) {
+ return;
+ }
/* get the mirror def vars */
if (index_mirr != -1) {
dv_mirr = &me->dvert[index_mirr];
- if (wp->flag & VP_ONLYVGROUP) {
+ if (wp->flag & VP_FLAG_VGROUP_RESTRICT) {
dw_mirr = defvert_find_index(dv_mirr, vgroup_mirr);
if (dw_mirr == NULL) {
@@ -1602,12 +738,28 @@ static void do_weight_paint_vertex_single(
dw_mirr = NULL;
}
+ if (!brush_use_accumulate(wp->paint.brush)) {
+ MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
+ MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
+ if (index_mirr != -1) {
+ defweight_prev_init(dvert_prev, me->dvert, index_mirr);
+ }
+
+ weight_prev = defvert_find_weight(dv_prev, wpi->active.index);
+ }
+ else {
+ weight_prev = dw->weight;
+ }
+
/* If there are no normalize-locks or multipaint,
* then there is no need to run the more complicated checks */
{
- dw->weight = wpaint_blend(wp, dw->weight, dw_prev->weight, alpha, paintweight,
- wpi->brush_alpha_value, wpi->do_flip);
+ float new_weight = wpaint_blend(
+ wp, weight_prev, alpha, paintweight,
+ wpi->brush_alpha_value, wpi->do_flip);
+
+ dw->weight = wpaint_clamp_monotonic(weight_prev, dw->weight, new_weight);
/* WATCH IT: take care of the ordering of applying mirror -> normalize,
* can give wrong results [#26193], least confusing if normalize is done last */
@@ -1666,13 +818,12 @@ static void do_weight_paint_vertex_single(
static void do_weight_paint_vertex_multi(
/* vars which remain the same for every vert */
- VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
+ const VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
/* vars which change on each stroke */
- const unsigned int index, float alpha, float paintweight)
+ const uint index, float alpha, float paintweight)
{
Mesh *me = ob->data;
MDeformVert *dv = &me->dvert[index];
- MDeformVert *dv_prev = &wp->wpaint_prev[index];
bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
/* mirror vars */
@@ -1680,7 +831,7 @@ static void do_weight_paint_vertex_multi(
MDeformVert *dv_mirr = NULL;
/* weights */
- float oldw, curw, neww, change, curw_mirr, change_mirr;
+ float curw, oldw, neww, change, curw_mirr, change_mirr;
/* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */
if (me->editflag & ME_EDIT_MIRROR_X) {
@@ -1689,11 +840,12 @@ static void do_weight_paint_vertex_multi(
if (index_mirr != -1 && index_mirr != index) {
dv_mirr = &me->dvert[index_mirr];
}
+ else {
+ index_mirr = -1;
+ }
}
/* compute weight change by applying the brush to average or sum of group weights */
- oldw = BKE_defvert_multipaint_collective_weight(
- dv_prev, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
curw = BKE_defvert_multipaint_collective_weight(
dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
@@ -1702,7 +854,22 @@ static void do_weight_paint_vertex_multi(
return;
}
- neww = wpaint_blend(wp, curw, oldw, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip);
+ if (!brush_use_accumulate(wp->paint.brush)) {
+ MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
+ MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
+ if (index_mirr != -1) {
+ defweight_prev_init(dvert_prev, me->dvert, index_mirr);
+ }
+
+ oldw = BKE_defvert_multipaint_collective_weight(
+ dv_prev, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
+ }
+ else {
+ oldw = curw;
+ }
+
+ neww = wpaint_blend(wp, oldw, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip);
+ neww = wpaint_clamp_monotonic(oldw, curw, neww);
change = neww / curw;
@@ -1756,9 +923,9 @@ static void do_weight_paint_vertex_multi(
static void do_weight_paint_vertex(
/* vars which remain the same for every vert */
- VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
+ const VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
/* vars which change on each stroke */
- const unsigned int index, float alpha, float paintweight)
+ const uint index, float alpha, float paintweight)
{
if (wpi->do_multipaint) {
do_weight_paint_vertex_multi(wp, ob, wpi, index, alpha, paintweight);
@@ -1768,13 +935,101 @@ static void do_weight_paint_vertex(
}
}
+
+/* Toggle operator for turning vertex paint mode on or off (copied from sculpt.c) */
+static void vertex_paint_init_session(Scene *scene, Object *ob)
+{
+ if (ob->sculpt == NULL) {
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+ BKE_sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, 0, false);
+ }
+}
+
+static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
+{
+ /* Create maps */
+ struct SculptVertexPaintGeomMap *gmap = NULL;
+ const Brush *brush = NULL;
+ if (ob->mode == OB_MODE_VERTEX_PAINT) {
+ gmap = &ob->sculpt->mode.vpaint.gmap;
+ brush = BKE_paint_brush(&ts->vpaint->paint);
+ ob->sculpt->mode_type = OB_MODE_VERTEX_PAINT;
+ }
+ else if (ob->mode == OB_MODE_WEIGHT_PAINT) {
+ gmap = &ob->sculpt->mode.wpaint.gmap;
+ brush = BKE_paint_brush(&ts->wpaint->paint);
+ ob->sculpt->mode_type = OB_MODE_WEIGHT_PAINT;
+ }
+ else {
+ ob->sculpt->mode_type = 0;
+ BLI_assert(0);
+ return;
+ }
+
+ Mesh *me = ob->data;
+
+ if (gmap->vert_to_loop == NULL) {
+ gmap->vert_map_mem = NULL;
+ gmap->vert_to_loop = NULL;
+ gmap->poly_map_mem = NULL;
+ gmap->vert_to_poly = NULL;
+ BKE_mesh_vert_loop_map_create(
+ &gmap->vert_to_loop,
+ &gmap->vert_map_mem,
+ me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
+ BKE_mesh_vert_poly_map_create(
+ &gmap->vert_to_poly,
+ &gmap->poly_map_mem,
+ me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
+ }
+
+ /* Create average brush arrays */
+ if (ob->mode == OB_MODE_VERTEX_PAINT) {
+ if (!brush_use_accumulate(brush)) {
+ if (ob->sculpt->mode.vpaint.previous_color == NULL) {
+ ob->sculpt->mode.vpaint.previous_color =
+ MEM_callocN(me->totloop * sizeof(uint), __func__);
+ }
+ }
+ else {
+ MEM_SAFE_FREE(ob->sculpt->mode.vpaint.previous_color);
+ }
+ }
+ else if (ob->mode == OB_MODE_WEIGHT_PAINT) {
+ if (!brush_use_accumulate(brush)) {
+ if (ob->sculpt->mode.wpaint.alpha_weight == NULL) {
+ ob->sculpt->mode.wpaint.alpha_weight =
+ MEM_callocN(me->totvert * sizeof(float), __func__);
+ }
+ if (ob->sculpt->mode.wpaint.dvert_prev == NULL) {
+ ob->sculpt->mode.wpaint.dvert_prev =
+ MEM_callocN(me->totvert * sizeof(MDeformVert), __func__);
+ MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
+ for (int i = 0; i < me->totvert; i++, dv++) {
+ /* Use to show this isn't initialized, never apply to the mesh data. */
+ dv->flag = 1;
+ }
+ }
+ }
+ else {
+ MEM_SAFE_FREE(ob->sculpt->mode.wpaint.alpha_weight);
+ if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
+ BKE_defvert_array_free_elems(ob->sculpt->mode.wpaint.dvert_prev, me->totvert);
+ MEM_freeN(ob->sculpt->mode.wpaint.dvert_prev);
+ ob->sculpt->mode.wpaint.dvert_prev = NULL;
+ }
+ }
+ }
+
+}
+
/* *************** set wpaint operator ****************** */
/**
* \note Keep in sync with #vpaint_mode_toggle_exec
*/
static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
-{
+{
Object *ob = CTX_data_active_object(C);
const int mode_flag = OB_MODE_WEIGHT_PAINT;
const bool is_mode_set = (ob->mode & mode_flag) != 0;
@@ -1804,13 +1059,21 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
ED_mesh_mirror_topo_table(NULL, NULL, 'e');
+ /* If the cache is not released by a cancel or a done, free it now. */
+ if (ob->sculpt->cache) {
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
+ }
+
+ BKE_sculptsession_free(ob);
+
paint_cursor_delete_textures();
}
else {
ob->mode |= mode_flag;
if (wp == NULL)
- wp = scene->toolsettings->wpaint = new_vpaint(1);
+ wp = scene->toolsettings->wpaint = new_vpaint();
paint_cursor_start(C, weight_paint_poll);
@@ -1819,8 +1082,14 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
/* weight paint specific */
ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's');
ED_vgroup_sync_from_pose(ob);
+
+ /* Create vertex/weight paint mode session data */
+ if (ob->sculpt) {
+ BKE_sculptsession_free(ob);
+ }
+ vertex_paint_init_session(scene, ob);
}
-
+
/* Weightpaint works by overriding colors in mesh,
* so need to make sure we recalc on enter and
* exit (exit needs doing regardless because we
@@ -1848,43 +1117,28 @@ static int paint_poll_test(bContext *C)
void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
{
-
+
/* identifiers */
ot->name = "Weight Paint Mode";
ot->idname = "PAINT_OT_weight_paint_toggle";
ot->description = "Toggle weight paint mode in 3D view";
-
+
/* api callbacks */
ot->exec = wpaint_mode_toggle_exec;
ot->poll = paint_poll_test;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
}
/* ************ weight paint operator ********** */
-enum eWPaintFlag {
- WPAINT_ENSURE_MIRROR = (1 << 0),
-};
-
-struct WPaintVGroupIndex {
- int active;
- int mirror;
-};
-
struct WPaintData {
ViewContext vc;
- int *indexar;
+ struct NormalAnglePrecalc normal_angle_precalc;
struct WeightPaintGroupData active, mirror;
- void *vp_handle;
- DMCoNo *vertexcosnos;
-
- float wpimat[3][3];
-
/* variables for auto normalize */
const bool *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */
const bool *lock_flags;
@@ -1894,110 +1148,138 @@ struct WPaintData {
int defbase_tot_sel; /* number of selected groups */
bool do_multipaint; /* true if multipaint enabled and multiple groups selected */
- /* variables for blur */
- struct {
- MeshElemMap *vmap;
- int *vmap_mem;
- } blur_data;
-
- BLI_Stack *accumulate_stack; /* for reuse (WPaintDefer) */
-
int defbase_tot;
+
+ /* original weight values for use in blur/smear */
+ float *precomputed_weight;
+ bool precomputed_weight_ready;
};
-/* ensure we have data on wpaint start, add if needed */
-static bool wpaint_ensure_data(
- bContext *C, wmOperator *op,
- enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index)
+/* Initialize the stroke cache invariants from operator properties */
+static void vwpaint_update_cache_invariants(
+ bContext *C, const VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
{
+ StrokeCache *cache;
Scene *scene = CTX_data_scene(C);
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ const Brush *brush = vp->paint.brush;
+ ViewContext *vc = paint_stroke_view_context(op->customdata);
Object *ob = CTX_data_active_object(C);
- Mesh *me = BKE_mesh_from_object(ob);
+ float mat[3][3];
+ float view_dir[3] = {0.0f, 0.0f, 1.0f};
+ int mode;
- if (vgroup_index) {
- vgroup_index->active = -1;
- vgroup_index->mirror = -1;
+ /* VW paint needs to allocate stroke cache before update is called. */
+ if (!ss->cache) {
+ cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
+ ss->cache = cache;
}
-
- if (scene->obedit) {
- return false;
+ else {
+ cache = ss->cache;
}
- if (me == NULL || me->totpoly == 0) {
- return false;
- }
+ /* Initial mouse location */
+ if (mouse)
+ copy_v2_v2(cache->initial_mouse, mouse);
+ else
+ zero_v2(cache->initial_mouse);
- /* if nothing was added yet, we make dverts and a vertex deform group */
- if (!me->dvert) {
- BKE_object_defgroup_data_create(&me->id);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
- }
+ mode = RNA_enum_get(op->ptr, "mode");
+ cache->invert = mode == BRUSH_STROKE_INVERT;
+ cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
+ /* not very nice, but with current events system implementation
+ * we can't handle brush appearance inversion hotkey separately (sergey) */
+ if (cache->invert) ups->draw_inverted = true;
+ else ups->draw_inverted = false;
- /* this happens on a Bone select, when no vgroup existed yet */
- if (ob->actdef <= 0) {
- Object *modob;
- if ((modob = modifiers_isDeformedByArmature(ob))) {
- Bone *actbone = ((bArmature *)modob->data)->act_bone;
- if (actbone) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name);
+ copy_v2_v2(cache->mouse, cache->initial_mouse);
+ /* Truly temporary data that isn't stored in properties */
+ cache->vc = vc;
+ cache->brush = brush;
+ cache->first_time = 1;
- if (pchan) {
- bDeformGroup *dg = defgroup_find_name(ob, pchan->name);
- if (dg == NULL) {
- dg = BKE_object_defgroup_add_name(ob, pchan->name); /* sets actdef */
- }
- else {
- int actdef = 1 + BLI_findindex(&ob->defbase, dg);
- BLI_assert(actdef >= 0);
- ob->actdef = actdef;
- }
- }
- }
- }
- }
- if (BLI_listbase_is_empty(&ob->defbase)) {
- BKE_object_defgroup_add(ob);
- }
+ /* cache projection matrix */
+ ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat);
- /* ensure we don't try paint onto an invalid group */
- if (ob->actdef <= 0) {
- BKE_report(op->reports, RPT_WARNING, "No active vertex group for painting, aborting");
- return false;
+ invert_m4_m4(ob->imat, ob->obmat);
+ copy_m3_m4(mat, cache->vc->rv3d->viewinv);
+ mul_m3_v3(mat, view_dir);
+ copy_m3_m4(mat, ob->imat);
+ mul_m3_v3(mat, view_dir);
+ normalize_v3_v3(cache->true_view_normal, view_dir);
+
+ copy_v3_v3(cache->view_normal, cache->true_view_normal);
+ cache->bstrength = BKE_brush_alpha_get(scene, brush);
+ cache->is_last_valid = false;
+}
+
+/* Initialize the stroke cache variants from operator properties */
+static void vwpaint_update_cache_variants(bContext *C, VPaint *vp, Object *ob, PointerRNA *ptr)
+{
+ Scene *scene = CTX_data_scene(C);
+ SculptSession *ss = ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ Brush *brush = BKE_paint_brush(&vp->paint);
+
+ /* This effects the actual brush radius, so things farther away
+ * are compared with a larger radius and vise versa. */
+ if (cache->first_time) {
+ RNA_float_get_array(ptr, "location", cache->true_location);
}
- if (vgroup_index) {
- vgroup_index->active = ob->actdef - 1;
+ RNA_float_get_array(ptr, "mouse", cache->mouse);
+
+ /* XXX: Use pressure value from first brush step for brushes which don't
+ * support strokes (grab, thumb). They depends on initial state and
+ * brush coord/pressure/etc.
+ * It's more an events design issue, which doesn't split coordinate/pressure/angle
+ * changing events. We should avoid this after events system re-design */
+ if (paint_supports_dynamic_size(brush, ePaintSculpt) || cache->first_time) {
+ cache->pressure = RNA_float_get(ptr, "pressure");
}
- if (flag & WPAINT_ENSURE_MIRROR) {
- if (me->editflag & ME_EDIT_MIRROR_X) {
- int mirror = wpaint_mirror_vgroup_ensure(ob, ob->actdef - 1);
- if (vgroup_index) {
- vgroup_index->mirror = mirror;
- }
+ /* Truly temporary data that isn't stored in properties */
+ if (cache->first_time) {
+ if (!BKE_brush_use_locked_size(scene, brush)) {
+ cache->initial_radius = paint_calc_object_space_radius(
+ cache->vc, cache->true_location, BKE_brush_size_get(scene, brush));
+ BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius);
+ }
+ else {
+ cache->initial_radius = BKE_brush_unprojected_radius_get(scene, brush);
}
}
- return true;
+ if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, ePaintSculpt)) {
+ cache->radius = cache->initial_radius * cache->pressure;
+ }
+ else {
+ cache->radius = cache->initial_radius;
+ }
+
+ cache->radius_squared = cache->radius * cache->radius;
+
+ if (ss->pbvh) {
+ BKE_pbvh_update(ss->pbvh, PBVH_UpdateRedraw, NULL);
+ BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
+ }
}
-static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2]))
+static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
{
Scene *scene = CTX_data_scene(C);
struct PaintStroke *stroke = op->customdata;
ToolSettings *ts = scene->toolsettings;
- VPaint *wp = ts->wpaint;
Object *ob = CTX_data_active_object(C);
Mesh *me = BKE_mesh_from_object(ob);
struct WPaintData *wpd;
struct WPaintVGroupIndex vgroup_index;
int defbase_tot, defbase_tot_sel;
bool *defbase_sel;
- const Brush *brush = BKE_paint_brush(&wp->paint);
-
- float mat[4][4], imat[4][4];
+ SculptSession *ss = ob->sculpt;
+ VPaint *vp = CTX_data_tool_settings(C)->wpaint;
- if (wpaint_ensure_data(C, op, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) {
+ if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) {
return false;
}
@@ -2048,6 +1330,8 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UN
wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData");
paint_stroke_set_mode_data(stroke, wpd);
view3d_set_viewcontext(C, &wpd->vc);
+ view_angle_limits_init(&wpd->normal_angle_precalc, vp->paint.brush->falloff_angle,
+ (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
wpd->active.index = vgroup_index.active;
wpd->mirror.index = vgroup_index.mirror;
@@ -2092,63 +1376,580 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UN
wpd->mirror.lock = tmpflags;
}
- /* painting on subsurfs should give correct points too, this returns me->totvert amount */
- wpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &wpd->vertexcosnos);
+ if (ELEM(vp->paint.brush->vertexpaint_tool, PAINT_BLEND_SMEAR, PAINT_BLEND_BLUR)) {
+ wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
+ }
- wpd->indexar = get_indexarray(me);
- copy_wpaint_prev(wp, me->dvert, me->totvert);
+ /* If not previously created, create vertex/weight paint mode session data */
+ vertex_paint_init_session(scene, ob);
+ vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
+ vertex_paint_init_session_data(ts, ob);
- if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
- BKE_mesh_vert_edge_vert_map_create(
- &wpd->blur_data.vmap, &wpd->blur_data.vmap_mem,
- me->medge, me->totvert, me->totedge);
+ if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
+ MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
+ for (int i = 0; i < me->totvert; i++, dv++) {
+ /* Use to show this isn't initialized, never apply to the mesh data. */
+ dv->flag = 1;
+ }
+ }
+
+ return true;
+}
+
+static float dot_vf3vs3(const float brushNormal[3], const short vertexNormal[3])
+{
+ float normal[3];
+ normal_short_to_float_v3(normal, vertexNormal);
+ return dot_v3v3(brushNormal, normal);
+}
+
+static void get_brush_alpha_data(
+ const Scene *scene, const SculptSession *ss, const Brush *brush,
+ float *r_brush_size_pressure, float *r_brush_alpha_value, float *r_brush_alpha_pressure)
+{
+ *r_brush_size_pressure =
+ BKE_brush_size_get(scene, brush) *
+ (BKE_brush_use_size_pressure(scene, brush) ? ss->cache->pressure : 1.0f);
+ *r_brush_alpha_value =
+ BKE_brush_alpha_get(scene, brush);
+ *r_brush_alpha_pressure =
+ (BKE_brush_use_alpha_pressure(scene, brush) ? ss->cache->pressure : 1.0f);
+}
+
+static float wpaint_get_active_weight(const MDeformVert *dv, const WeightPaintInfo *wpi)
+{
+ if (wpi->do_multipaint) {
+ float weight = BKE_defvert_multipaint_collective_weight(
+ dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
+
+ CLAMP(weight, 0.0f, 1.0f);
+ return weight;
+ }
+ else {
+ return defvert_find_weight(dv, wpi->active.index);
+ }
+}
+
+static void do_wpaint_precompute_weight_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+{
+ SculptThreadedTaskData *data = userdata;
+ const MDeformVert *dv = &data->me->dvert[n];
+
+ data->wpd->precomputed_weight[n] = wpaint_get_active_weight(dv, data->wpi);
+}
+
+static void precompute_weight_values(
+ bContext *C, Object *ob, Brush *brush, struct WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me)
+{
+ if (wpd->precomputed_weight_ready && !brush_use_accumulate(brush))
+ return;
+
+ /* threaded loop over vertices */
+ SculptThreadedTaskData data = {
+ .C = C, .ob = ob, .wpd = wpd, .wpi = wpi, .me = me,
+ };
+
+ BLI_task_parallel_range_ex(
+ 0, me->totvert, &data, NULL, 0, do_wpaint_precompute_weight_cb_ex,
+ true, false);
+
+ wpd->precomputed_weight_ready = true;
+}
+
+static void do_wpaint_brush_blur_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
+
+ const Brush *brush = data->brush;
+ const StrokeCache *cache = ss->cache;
+ Scene *scene = CTX_data_scene(data->C);
+
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+ const float *sculpt_normal_frontface =
+ sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* For grid based pbvh, take the vert whose loop coopresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
+ const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
+ const char v_flag = data->me->mvert[v_index].flag;
+ /* If the vertex is selected */
+ if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
+ /* Get the average poly weight */
+ int total_hit_loops = 0;
+ float weight_final = 0.0f;
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const MPoly *mp = &data->me->mpoly[p_index];
+
+ total_hit_loops += mp->totloop;
+ for (int k = 0; k < mp->totloop; k++) {
+ const int l_index = mp->loopstart + k;
+ const MLoop *ml = &data->me->mloop[l_index];
+ weight_final += data->wpd->precomputed_weight[ml->v];
+ }
+ }
+
+ /* Apply the weight to the vertex. */
+ if (total_hit_loops != 0) {
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
+ (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
+ {
+ const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
+ const float final_alpha =
+ brush_fade * brush_strength *
+ grid_alpha * brush_alpha_pressure;
+
+ if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
+ if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
+ ss->mode.wpaint.alpha_weight[v_index] = final_alpha;
+ }
+ else {
+ continue;
+ }
+ }
+
+ weight_final /= total_hit_loops;
+ /* Only paint visable verts */
+ do_weight_paint_vertex(
+ data->vp, data->ob, data->wpi,
+ v_index, final_alpha, weight_final);
+ }
+ }
+ }
+ }
}
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_wpaint_brush_smear_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
+
+ const Brush *brush = data->brush;
+ const Scene *scene = CTX_data_scene(data->C);
+ const StrokeCache *cache = ss->cache;
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ float brush_dir[3];
+
+ sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
+ project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
+
+ if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+ const float *sculpt_normal_frontface =
+ sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* For grid based pbvh, take the vert whose loop cooresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
+ const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv_curr = &data->me->mvert[v_index];
+
+ /* If the vertex is selected */
+ if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) {
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
+ (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
+ {
+ bool do_color = false;
+ /* Minimum dot product between brush direction and current
+ * to neighbor direction is 0.0, meaning orthogonal. */
+ float stroke_dot_max = 0.0f;
+
+ /* Get the color of the loop in the opposite direction of the brush movement
+ * (this callback is specifically for smear.) */
+ float weight_final = 0.0;
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const MPoly *mp = &data->me->mpoly[p_index];
+ const MLoop *ml_other = &data->me->mloop[mp->loopstart];
+ for (int k = 0; k < mp->totloop; k++, ml_other++) {
+ const uint v_other_index = ml_other->v;
+ if (v_other_index != v_index) {
+ const MVert *mv_other = &data->me->mvert[v_other_index];
+
+ /* Get the direction from the selected vert to the neighbor. */
+ float other_dir[3];
+ sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
+ project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
+
+ normalize_v3(other_dir);
+
+ const float stroke_dot = dot_v3v3(other_dir, brush_dir);
+
+ if (stroke_dot > stroke_dot_max) {
+ stroke_dot_max = stroke_dot;
+ weight_final = data->wpd->precomputed_weight[v_other_index];
+ do_color = true;
+ }
+ }
+ }
+ }
+ /* Apply weight to vertex */
+ if (do_color) {
+ const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
+ const float final_alpha =
+ brush_fade * brush_strength *
+ grid_alpha * brush_alpha_pressure;
+
+ if (final_alpha <= 0.0f)
+ continue;
+
+ do_weight_paint_vertex(
+ data->vp, data->ob, data->wpi,
+ v_index, final_alpha, (float)weight_final);
+ }
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
- if ((brush->vertexpaint_tool == PAINT_BLEND_BLUR) &&
- (brush->flag & BRUSH_ACCUMULATE))
+static void do_wpaint_brush_draw_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
+ const Scene *scene = CTX_data_scene(data->C);
+
+ const Brush *brush = data->brush;
+ const StrokeCache *cache = ss->cache;
+ /* note: normally `BKE_brush_weight_get(scene, brush)` is used,
+ * however in this case we calculate a new weight each time. */
+ const float paintweight = data->strength;
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+ const float *sculpt_normal_frontface =
+ sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- wpd->accumulate_stack = BLI_stack_new(sizeof(struct WPaintDefer), __func__);
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* Note: grids are 1:1 with corners (aka loops).
+ * For multires, take the vert whose loop cooresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
+ const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
+
+ const char v_flag = data->me->mvert[v_index].flag;
+ /* If the vertex is selected */
+ if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
+ (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
+ {
+ const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
+ const float final_alpha = brush_fade * brush_strength * grid_alpha * brush_alpha_pressure;
+
+ if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
+ if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
+ ss->mode.wpaint.alpha_weight[v_index] = final_alpha;
+ }
+ else {
+ continue;
+ }
+ }
+
+ do_weight_paint_vertex(
+ data->vp, data->ob, data->wpi,
+ v_index, final_alpha, paintweight);
+ }
+ }
+ }
}
+ BKE_pbvh_vertex_iter_end;
+}
- /* imat for normals */
- mul_m4_m4m4(mat, wpd->vc.rv3d->viewmat, ob->obmat);
- invert_m4_m4(imat, mat);
- copy_m3_m4(wpd->wpimat, imat);
+static void do_wpaint_brush_calc_average_weight_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
- return true;
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+
+ struct WPaintAverageAccum *accum = (struct WPaintAverageAccum *)data->custom_data + n;
+ accum->len = 0;
+ accum->value = 0.0;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+ const float *sculpt_normal_frontface =
+ sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
+ if (angle_cos > 0.0 && BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) {
+ const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
+ // const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
+ const char v_flag = data->me->mvert[v_index].flag;
+
+ /* If the vertex is selected. */
+ if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
+ const MDeformVert *dv = &data->me->dvert[v_index];
+ accum->len += 1;
+ accum->value += wpaint_get_active_weight(dv, data->wpi);
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
-static float wpaint_blur_weight_single(const MDeformVert *dv, const WeightPaintInfo *wpi)
+static void calculate_average_weight(SculptThreadedTaskData *data, PBVHNode **UNUSED(nodes), int totnode)
{
- return defvert_find_weight(dv, wpi->active.index);
+ struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
+ data->custom_data = accum;
+
+ BLI_task_parallel_range_ex(
+ 0, totnode, data, NULL, 0, do_wpaint_brush_calc_average_weight_cb_ex,
+ ((data->sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+
+ uint accum_len = 0;
+ double accum_weight = 0.0;
+ for (int i = 0; i < totnode; i++) {
+ accum_len += accum[i].len;
+ accum_weight += accum[i].value;
+ }
+ if (accum_len != 0) {
+ accum_weight /= accum_len;
+ data->strength = (float)accum_weight;
+ }
+
+ MEM_SAFE_FREE(data->custom_data); /* 'accum' */
}
-static float wpaint_blur_weight_multi(const MDeformVert *dv, const WeightPaintInfo *wpi)
+
+static void wpaint_paint_leaves(
+ bContext *C, Object *ob, Sculpt *sd, VPaint *vp, struct WPaintData *wpd, WeightPaintInfo *wpi,
+ Mesh *me, PBVHNode **nodes, int totnode)
{
- float weight = BKE_defvert_multipaint_collective_weight(
- dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
- CLAMP(weight, 0.0f, 1.0f);
- return weight;
+ Scene *scene = CTX_data_scene(C);
+ const Brush *brush = ob->sculpt->cache->brush;
+
+ /* threaded loop over nodes */
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .wpd = wpd, .wpi = wpi, .me = me, .C = C,
+ };
+
+ /* Use this so average can modify its weight without touching the brush. */
+ data.strength = BKE_brush_weight_get(scene, brush);
+
+ /* current mirroring code cannot be run in parallel */
+ bool use_threading = !(me->editflag & ME_EDIT_MIRROR_X);
+
+ switch (brush->vertexpaint_tool) {
+ case PAINT_BLEND_AVERAGE:
+ calculate_average_weight(&data, nodes, totnode);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0,
+ do_wpaint_brush_draw_task_cb_ex, use_threading, false);
+ break;
+ case PAINT_BLEND_SMEAR:
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0,
+ do_wpaint_brush_smear_task_cb_ex, use_threading, false);
+ break;
+ case PAINT_BLEND_BLUR:
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0,
+ do_wpaint_brush_blur_task_cb_ex, use_threading, false);
+ break;
+ default:
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0,
+ do_wpaint_brush_draw_task_cb_ex, use_threading, false);
+ break;
+ }
}
-static float wpaint_blur_weight_calc_from_connected(
- const MDeformVert *dvert, WeightPaintInfo *wpi, struct WPaintData *wpd, const unsigned int vidx,
- float (*blur_weight_func)(const MDeformVert *, const WeightPaintInfo *))
+static PBVHNode **vwpaint_pbvh_gather_generic(
+ Object *ob, VPaint *wp, Sculpt *sd, Brush *brush, int *r_totnode)
{
- const MeshElemMap *map = &wpd->blur_data.vmap[vidx];
- float paintweight;
- if (map->count != 0) {
- paintweight = 0.0f;
- for (int j = 0; j < map->count; j++) {
- paintweight += blur_weight_func(&dvert[map->indices[j]], wpi);
+ SculptSession *ss = ob->sculpt;
+ const bool use_normal = vwpaint_use_normal(wp);
+ PBVHNode **nodes = NULL;
+
+ /* Build a list of all nodes that are potentially within the brush's area of influence */
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = ss->cache->radius_squared,
+ .original = true,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
+ if (use_normal) {
+ sculpt_pbvh_calc_area_normal(brush, ob, nodes, *r_totnode, true, ss->cache->sculpt_normal_symm);
+ }
+ else {
+ zero_v3(ss->cache->sculpt_normal_symm);
}
- paintweight /= map->count;
}
else {
- paintweight = blur_weight_func(&dvert[vidx], wpi);
+ struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
+ dist_squared_ray_to_aabb_v3_precalc(&dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal);
+ SculptSearchCircleData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = ss->cache->radius_squared,
+ .original = true,
+ .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode);
+ if (use_normal) {
+ copy_v3_v3(ss->cache->sculpt_normal_symm, ss->cache->view_normal);
+ }
+ else {
+ zero_v3(ss->cache->sculpt_normal_symm);
+ }
}
+ return nodes;
+}
+
+static void wpaint_do_paint(
+ bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi,
+ Mesh *me, Brush *brush, const char symm, const int axis, const int i, const float angle)
+{
+ SculptSession *ss = ob->sculpt;
+ ss->cache->radial_symmetry_pass = i;
+ sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
+
+ int totnode;
+ PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, wp, sd, brush, &totnode);
+
+ wpaint_paint_leaves(C, ob, sd, wp, wpd, wpi, me, nodes, totnode);
+
+ if (nodes)
+ MEM_freeN(nodes);
+}
- return paintweight;
+static void wpaint_do_radial_symmetry(
+ bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi,
+ Mesh *me, Brush *brush, const char symm, const int axis)
+{
+ for (int i = 1; i < wp->radial_symm[axis - 'X']; i++) {
+ const float angle = (2.0 * M_PI) * i / wp->radial_symm[axis - 'X'];
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, axis, i, angle);
+ }
+}
+
+/* near duplicate of: sculpt.c's, 'do_symmetrical_brush_actions' and 'vpaint_do_symmetrical_brush_actions'. */
+static void wpaint_do_symmetrical_brush_actions(
+ bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi)
+{
+ Brush *brush = BKE_paint_brush(&wp->paint);
+ Mesh *me = ob->data;
+ SculptSession *ss = ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ const char symm = wp->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ int i = 0;
+
+ /* initial stroke */
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X');
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Y');
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Z');
+
+ cache->symmetry = symm;
+
+ /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
+ for (i = 1; i <= symm; i++) {
+ if ((symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+ cache->mirror_symmetry_pass = i;
+ cache->radial_symmetry_pass = 0;
+ sculpt_cache_calc_brushdata_symm(cache, i, 0, 0);
+
+ if (i & (1 << 0)) {
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X');
+ }
+ if (i & (1 << 1)) {
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y');
+ }
+ if (i & (1 << 2)) {
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z');
+ }
+ }
+ }
+ copy_v3_v3(cache->true_last_location, cache->true_location);
+ cache->is_last_valid = true;
}
static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
@@ -2159,24 +1960,17 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
Brush *brush = BKE_paint_brush(&wp->paint);
struct WPaintData *wpd = paint_stroke_mode_data(stroke);
ViewContext *vc;
- Object *ob;
- Mesh *me;
+ Object *ob = CTX_data_active_object(C);
+
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ vwpaint_update_cache_variants(C, wp, ob, itemptr);
+
float mat[4][4];
- float paintweight;
- int *indexar;
- unsigned int index, totindex;
float mval[2];
- const bool use_blur = (brush->vertexpaint_tool == PAINT_BLEND_BLUR);
- bool use_vert_sel;
- bool use_face_sel;
- bool use_depth;
-
- const float pressure = RNA_float_get(itemptr, "pressure");
- const float brush_size_pressure =
- BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f);
+
const float brush_alpha_value = BKE_brush_alpha_get(scene, brush);
- const float brush_alpha_pressure =
- brush_alpha_value * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f);
/* intentionally don't initialize as NULL, make sure we initialize all members below */
WeightPaintInfo wpi;
@@ -2189,21 +1983,15 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
return;
}
- float (*blur_weight_func)(const MDeformVert *, const WeightPaintInfo *) =
- wpd->do_multipaint ? wpaint_blur_weight_multi : wpaint_blur_weight_single;
-
vc = &wpd->vc;
ob = vc->obact;
- me = ob->data;
- indexar = wpd->indexar;
-
+
view3d_operator_needs_opengl(C);
ED_view3d_init_mats_rv3d(ob, vc->rv3d);
/* load projection matrix */
mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
- RNA_float_get_array(itemptr, "mouse", mval);
/* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
wpi.defbase_tot = wpd->defbase_tot;
@@ -2221,180 +2009,51 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
wpi.brush_alpha_value = brush_alpha_value;
/* *** done setting up WeightPaintInfo *** */
-
-
- swap_m4m4(wpd->vc.rv3d->persmat, mat);
-
- use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- use_depth = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
-
- /* which faces are involved */
- if (use_depth) {
- char editflag_prev = me->editflag;
-
- /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */
- me->editflag &= ~ME_EDIT_PAINT_VERT_SEL;
- if (use_vert_sel) {
- /* Ugly x2, we need this so hidden faces don't draw */
- me->editflag |= ME_EDIT_PAINT_FACE_SEL;
- }
- totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure);
- me->editflag = editflag_prev;
-
- if (use_face_sel && me->totpoly) {
- MPoly *mpoly = me->mpoly;
- for (index = 0; index < totindex; index++) {
- if (indexar[index] && indexar[index] <= me->totpoly) {
- MPoly *mp = &mpoly[indexar[index] - 1];
-
- if ((mp->flag & ME_FACE_SEL) == 0) {
- indexar[index] = 0;
- }
- }
- }
- }
- }
- else {
- indexar = NULL;
+ if (wpd->precomputed_weight) {
+ precompute_weight_values(C, ob, brush, wpd, &wpi, ob->data);
}
- /* incase we have modifiers */
- ED_vpaint_proj_handle_update(wpd->vp_handle, vc->ar, mval);
+ wpaint_do_symmetrical_brush_actions(C, ob, wp, sd, wpd, &wpi);
- /* make sure each vertex gets treated only once */
- /* and calculate filter weight */
- paintweight = BKE_brush_weight_get(scene, brush);
+ swap_m4m4(vc->rv3d->persmat, mat);
- if (use_depth) {
- for (index = 0; index < totindex; index++) {
- if (indexar[index] && indexar[index] <= me->totpoly) {
- MPoly *mpoly = me->mpoly + (indexar[index] - 1);
- MLoop *ml = me->mloop + mpoly->loopstart;
- int i;
+ /* calculate pivot for rotation around seletion if needed */
+ /* also needed for "View Selected" on last stroke */
+ paint_last_stroke_update(scene, vc->ar, mval);
- if (use_vert_sel) {
- for (i = 0; i < mpoly->totloop; i++, ml++) {
- me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT);
- }
- }
- else {
- for (i = 0; i < mpoly->totloop; i++, ml++) {
- me->dvert[ml->v].flag = 1;
- }
- }
- }
- }
- }
- else {
- const unsigned int totvert = me->totvert;
- unsigned int i;
+ DAG_id_tag_update(ob->data, 0);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ swap_m4m4(wpd->vc.rv3d->persmat, mat);
- /* in the case of face selection we need to flush */
- if (use_vert_sel || use_face_sel) {
- for (i = 0; i < totvert; i++) {
- me->dvert[i].flag = me->mvert[i].flag & SELECT;
- }
- }
- else {
- for (i = 0; i < totvert; i++) {
- me->dvert[i].flag = SELECT;
- }
+ rcti r;
+ if (sculpt_get_redraw_rect(vc->ar, CTX_wm_region_view3d(C), ob, &r)) {
+ if (ss->cache) {
+ ss->cache->current_r = r;
}
- }
- /* accumulate means we refer to the previous,
- * which is either the last update, or when we started painting */
- BLI_Stack *accumulate_stack = wpd->accumulate_stack;
- const bool use_accumulate = (accumulate_stack != NULL);
- BLI_assert(accumulate_stack == NULL || BLI_stack_is_empty(accumulate_stack));
-
- const MDeformVert *dvert_prev = use_accumulate ? me->dvert : wp->wpaint_prev;
-
-#define WP_PAINT(v_idx_var) \
- { \
- unsigned int vidx = v_idx_var; \
- if (me->dvert[vidx].flag) { \
- const float alpha = calc_vp_alpha_col_dl( \
- wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \
- mval, brush_size_pressure, brush_alpha_pressure, NULL); \
- if (alpha) { \
- if (use_blur) { \
- paintweight = wpaint_blur_weight_calc_from_connected( \
- dvert_prev, &wpi, wpd, vidx, blur_weight_func); \
- } \
- if (use_accumulate) { \
- struct WPaintDefer *dweight = BLI_stack_push_r(accumulate_stack); \
- dweight->index = vidx; \
- dweight->alpha = alpha; \
- dweight->weight = paintweight; \
- } \
- else { \
- do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \
- } \
- } \
- me->dvert[vidx].flag = 0; \
- } \
- } (void)0
-
- if (use_depth) {
- for (index = 0; index < totindex; index++) {
-
- if (indexar[index] && indexar[index] <= me->totpoly) {
- MPoly *mpoly = me->mpoly + (indexar[index] - 1);
- MLoop *ml = me->mloop + mpoly->loopstart;
- int i;
-
- for (i = 0; i < mpoly->totloop; i++, ml++) {
- WP_PAINT(ml->v);
- }
- }
+ /* previous is not set in the current cache else
+ * the partial rect will always grow */
+ if (ss->cache) {
+ if (!BLI_rcti_is_empty(&ss->cache->previous_r))
+ BLI_rcti_union(&r, &ss->cache->previous_r);
}
- }
- else {
- const unsigned int totvert = me->totvert;
- unsigned int i;
- for (i = 0; i < totvert; i++) {
- WP_PAINT(i);
- }
- }
-#undef WP_PAINT
+ r.xmin += vc->ar->winrct.xmin - 2;
+ r.xmax += vc->ar->winrct.xmin + 2;
+ r.ymin += vc->ar->winrct.ymin - 2;
+ r.ymax += vc->ar->winrct.ymin + 2;
- if (use_accumulate) {
- unsigned int defer_count = BLI_stack_count(accumulate_stack);
- while (defer_count--) {
- struct WPaintDefer *dweight = BLI_stack_peek(accumulate_stack);
- do_weight_paint_vertex(wp, ob, &wpi, dweight->index, dweight->alpha, dweight->weight);
- BLI_stack_discard(accumulate_stack);
- }
+ ss->partial_redraw = 1;
}
-
-
- /* *** free wpi members */
- /* *** done freeing wpi members */
-
-
- swap_m4m4(vc->rv3d->persmat, mat);
-
- /* calculate pivot for rotation around seletion if needed */
- /* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, vc->ar, mval);
-
- DAG_id_tag_update(ob->data, 0);
- ED_region_tag_redraw(vc->ar);
+ ED_region_tag_redraw_partial(vc->ar, &r);
}
static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
struct WPaintData *wpd = paint_stroke_mode_data(stroke);
-
+
if (wpd) {
- ED_vpaint_proj_handle_free(wpd->vp_handle);
- MEM_freeN(wpd->indexar);
-
if (wpd->defbase_sel)
MEM_freeN((void *)wpd->defbase_sel);
if (wpd->vgroup_validmap)
@@ -2405,29 +2064,17 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN((void *)wpd->active.lock);
if (wpd->mirror.lock)
MEM_freeN((void *)wpd->mirror.lock);
-
- if (wpd->blur_data.vmap) {
- MEM_freeN(wpd->blur_data.vmap);
- }
- if (wpd->blur_data.vmap_mem) {
- MEM_freeN(wpd->blur_data.vmap_mem);
- }
-
- if (wpd->accumulate_stack) {
- BLI_stack_free(wpd->accumulate_stack);
- }
+ if (wpd->precomputed_weight)
+ MEM_freeN(wpd->precomputed_weight);
MEM_freeN(wpd);
}
-
- /* frees prev buffer */
- copy_wpaint_prev(ts->wpaint, NULL, 0);
-
+
/* and particles too */
if (ob->particlesystem.first) {
ParticleSystem *psys;
int i;
-
+
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
for (i = 0; i < PSYS_TOT_VG; i++) {
if (psys->vgroup[i] == ob->actdef) {
@@ -2441,6 +2088,9 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
DAG_id_tag_update(ob->data, 0);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
}
@@ -2448,10 +2098,11 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
- op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start,
- wpaint_stroke_update_step, NULL,
- wpaint_stroke_done, event->type);
-
+ op->customdata = paint_stroke_new(
+ C, op, sculpt_stroke_get_location, wpaint_stroke_test_start,
+ wpaint_stroke_update_step, NULL,
+ wpaint_stroke_done, event->type);
+
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
paint_stroke_data_free(op);
return OPERATOR_FINISHED;
@@ -2461,15 +2112,16 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
OPERATOR_RETVAL_CHECK(retval);
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
-
+
return OPERATOR_RUNNING_MODAL;
}
static int wpaint_exec(bContext *C, wmOperator *op)
{
- op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start,
- wpaint_stroke_update_step, NULL,
- wpaint_stroke_done, 0);
+ op->customdata = paint_stroke_new(
+ C, op, sculpt_stroke_get_location, wpaint_stroke_test_start,
+ wpaint_stroke_update_step, NULL,
+ wpaint_stroke_done, 0);
/* frees op->customdata */
paint_stroke_exec(C, op);
@@ -2479,64 +2131,33 @@ static int wpaint_exec(bContext *C, wmOperator *op)
static void wpaint_cancel(bContext *C, wmOperator *op)
{
+ Object *ob = CTX_data_active_object(C);
+ if (ob->sculpt->cache) {
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
+ }
+
paint_stroke_cancel(C, op);
}
void PAINT_OT_weight_paint(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Weight Paint";
ot->idname = "PAINT_OT_weight_paint";
ot->description = "Paint a stroke in the current vertex group's weights";
-
+
/* api callbacks */
ot->invoke = wpaint_invoke;
ot->modal = paint_stroke_modal;
ot->exec = wpaint_exec;
ot->poll = weight_paint_poll;
ot->cancel = wpaint_cancel;
-
+
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- paint_stroke_operator_properties(ot);
-}
-
-static int weight_paint_set_exec(bContext *C, wmOperator *op)
-{
- struct Scene *scene = CTX_data_scene(C);
- Object *obact = CTX_data_active_object(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
- float vgroup_weight = BKE_brush_weight_get(scene, brush);
- if (wpaint_ensure_data(C, op, WPAINT_ENSURE_MIRROR, NULL) == false) {
- return OPERATOR_CANCELLED;
- }
-
- if (ED_wpaint_fill(scene->toolsettings->wpaint, obact, vgroup_weight)) {
- ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-void PAINT_OT_weight_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Weight";
- ot->idname = "PAINT_OT_weight_set";
- ot->description = "Fill the active vertex group with the current paint weight";
-
- /* api callbacks */
- ot->exec = weight_paint_set_exec;
- ot->poll = mask_paint_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ paint_stroke_operator_properties(ot);
}
/* ************ set / clear vertex paint mode ********** */
@@ -2545,7 +2166,7 @@ void PAINT_OT_weight_set(wmOperatorType *ot)
* \note Keep in sync with #wpaint_mode_toggle_exec
*/
static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
-{
+{
Object *ob = CTX_data_active_object(C);
const int mode_flag = OB_MODE_VERTEX_PAINT;
const bool is_mode_set = (ob->mode & mode_flag) != 0;
@@ -2560,7 +2181,7 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
}
me = BKE_mesh_from_object(ob);
-
+
/* toggle: end vpaint */
if (is_mode_set) {
ob->mode &= ~mode_flag;
@@ -2568,44 +2189,62 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
BKE_mesh_flush_select_from_polys(me);
}
+ else if (me->editflag & ME_EDIT_PAINT_VERT_SEL) {
+ BKE_mesh_flush_select_from_verts(me);
+ }
+
+ /* If the cache is not released by a cancel or a done, free it now. */
+ if (ob->sculpt->cache) {
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
+ }
+
+ BKE_sculptsession_free(ob);
paint_cursor_delete_textures();
}
else {
ob->mode |= mode_flag;
- if (me->mloopcol == NULL) {
- make_vertexcol(ob);
- }
+ ED_mesh_color_ensure(me, NULL);
if (vp == NULL)
- vp = scene->toolsettings->vpaint = new_vpaint(0);
-
+ vp = scene->toolsettings->vpaint = new_vpaint();
+
paint_cursor_start(C, vertex_paint_poll);
BKE_paint_init(scene, ePaintVertex, PAINT_CURSOR_VERTEX_PAINT);
+
+ /* Create vertex/weight paint mode session data */
+ if (ob->sculpt) {
+ if (ob->sculpt->cache) {
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
+ }
+ BKE_sculptsession_free(ob);
+ }
+ vertex_paint_init_session(scene, ob);
}
-
+
/* update modifier stack for mapping requirements */
DAG_id_tag_update(&me->id, 0);
-
+
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
-
+
return OPERATOR_FINISHED;
}
void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Vertex Paint Mode";
ot->idname = "PAINT_OT_vertex_paint_toggle";
ot->description = "Toggle the vertex paint mode in 3D view";
-
+
/* api callbacks */
ot->exec = vpaint_mode_toggle_exec;
ot->poll = paint_poll_test;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -2620,7 +2259,7 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
* - validate context (add mcol)
* - create customdata storage
* - call paint once (mouse click)
- * - add modal handler
+ * - add modal handler
*
* Operator->modal()
* - for every mousemove, apply vertex paint
@@ -2637,15 +2276,14 @@ typedef struct PolyFaceMap {
int facenr;
} PolyFaceMap;
-typedef struct VPaintData {
+struct VPaintData {
ViewContext vc;
- unsigned int paintcol;
- int *indexar;
+ struct NormalAnglePrecalc normal_angle_precalc;
- struct VertProjHandle *vp_handle;
- DMCoNo *vertexcosnos;
+ uint paintcol;
- float vpimat[3][3];
+ struct VertProjHandle *vp_handle;
+ struct DMCoNo *vertexcosnos;
/* modify 'me->mcol' directly, since the derived mesh is drawing from this
* array, otherwise we need to refresh the modifier stack */
@@ -2656,9 +2294,15 @@ typedef struct VPaintData {
bool *mlooptag;
bool is_texbrush;
-} VPaintData;
-static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float UNUSED(mouse[2]))
+ /* Special storage for smear brush, avoid feedback loop - update each step. */
+ struct {
+ uint *color_prev;
+ uint *color_curr;
+ } smear;
+};
+
+static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
{
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@@ -2668,26 +2312,24 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
struct VPaintData *vpd;
Object *ob = CTX_data_active_object(C);
Mesh *me;
- float mat[4][4], imat[4][4];
+ SculptSession *ss = ob->sculpt;
/* context checks could be a poll() */
me = BKE_mesh_from_object(ob);
if (me == NULL || me->totpoly == 0)
return false;
-
- if (me->mloopcol == NULL)
- make_vertexcol(ob);
+
+ ED_mesh_color_ensure(me, NULL);
if (me->mloopcol == NULL)
return false;
/* make mode data storage */
- vpd = MEM_callocN(sizeof(struct VPaintData), "VPaintData");
+ vpd = MEM_callocN(sizeof(*vpd), "VPaintData");
paint_stroke_set_mode_data(stroke, vpd);
view3d_set_viewcontext(C, &vpd->vc);
-
- vpd->vp_handle = ED_vpaint_proj_handle_create(vpd->vc.scene, ob, &vpd->vertexcosnos);
+ view_angle_limits_init(&vpd->normal_angle_precalc, vp->paint.brush->falloff_angle,
+ (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
- vpd->indexar = get_indexarray(me);
vpd->paintcol = vpaint_get_current_col(scene, vp);
vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) &&
@@ -2709,84 +2351,564 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
vpd->mlooptag = MEM_mallocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
}
- /* for filtering */
- copy_vpaint_prev(vp, (unsigned int *)me->mloopcol, me->totloop);
-
- /* some old cruft to sort out later */
- mul_m4_m4m4(mat, vpd->vc.rv3d->viewmat, ob->obmat);
- invert_m4_m4(imat, mat);
- copy_m3_m4(vpd->vpimat, imat);
+ if (brush->vertexpaint_tool == PAINT_BLEND_SMEAR) {
+ vpd->smear.color_prev = MEM_mallocN(sizeof(uint) * me->totloop, __func__);
+ memcpy(vpd->smear.color_prev, me->mloopcol, sizeof(uint) * me->totloop);
+ vpd->smear.color_curr = MEM_dupallocN(vpd->smear.color_prev);
+ }
+
+ /* Create projection handle */
+ if (vpd->is_texbrush) {
+ ob->sculpt->building_vp_handle = true;
+ vpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &vpd->vertexcosnos);
+ ob->sculpt->building_vp_handle = false;
+ }
+
+ /* If not previously created, create vertex/weight paint mode session data */
+ vertex_paint_init_session(scene, ob);
+ vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
+ vertex_paint_init_session_data(ts, ob);
+
+ if (ob->sculpt->mode.vpaint.previous_color != NULL) {
+ memset(ob->sculpt->mode.vpaint.previous_color, 0, sizeof(uint) * me->totloop);
+ }
return 1;
}
-static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me,
- const unsigned int index, const float mval[2],
- const float brush_size_pressure, const float brush_alpha_pressure)
+static void do_vpaint_brush_calc_average_color_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
{
- ViewContext *vc = &vpd->vc;
- Brush *brush = BKE_paint_brush(&vp->paint);
- MPoly *mpoly = &me->mpoly[index];
- MLoop *ml;
- unsigned int *lcol = ((unsigned int *)me->mloopcol) + mpoly->loopstart;
- unsigned int *lcolorig = ((unsigned int *)vp->vpaint_prev) + mpoly->loopstart;
- bool *mlooptag = (vpd->mlooptag) ? vpd->mlooptag + mpoly->loopstart : NULL;
- float alpha;
- int i, j;
- int totloop = mpoly->totloop;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
- int brush_alpha_pressure_i = (int)(brush_alpha_pressure * 255.0f);
+ StrokeCache *cache = ss->cache;
+ uint *lcol = data->lcol;
+ char *col;
+ const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
- if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
- unsigned int blend[4] = {0};
- unsigned int tcol;
- char *col;
+ struct VPaintAverageAccum *accum = (struct VPaintAverageAccum *)data->custom_data + n;
+ accum->len = 0;
+ memset(accum->value, 0, sizeof(accum->value));
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
- for (j = 0; j < totloop; j++) {
- col = (char *)(lcol + j);
- blend[0] += col[0];
- blend[1] += col[1];
- blend[2] += col[2];
- blend[3] += col[3];
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
+ if (BKE_brush_curve_strength(data->brush, 0.0, cache->radius) > 0.0) {
+ /* If the vertex is selected for painting. */
+ const MVert *mv = &data->me->mvert[v_index];
+ if (!use_vert_sel || mv->flag & SELECT) {
+ accum->len += gmap->vert_to_loop[v_index].count;
+ /* if a vertex is within the brush region, then add it's color to the blend. */
+ for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) {
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ col = (char *)(&lcol[l_index]);
+ /* Color is squared to compensate the sqrt color encoding. */
+ accum->value[0] += col[0] * col[0];
+ accum->value[1] += col[1] * col[1];
+ accum->value[2] += col[2] * col[2];
+ }
+ }
+ }
}
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static float tex_color_alpha_ubyte(
+ SculptThreadedTaskData *data, const float v_co[3],
+ uint *r_color)
+{
+ float rgba[4];
+ float rgba_br[3];
+ tex_color_alpha(data->vp, &data->vpd->vc, v_co, rgba);
+ rgb_uchar_to_float(rgba_br, (const uchar *)&data->vpd->paintcol);
+ mul_v3_v3(rgba_br, rgba);
+ rgb_float_to_uchar((uchar *)r_color, rgba_br);
+ return rgba[3];
+}
+
+static void do_vpaint_brush_draw_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+
+ const Brush *brush = data->brush;
+ const StrokeCache *cache = ss->cache;
+ uint *lcol = data->lcol;
+ const Scene *scene = CTX_data_scene(data->C);
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- blend[0] = divide_round_i(blend[0], totloop);
- blend[1] = divide_round_i(blend[1], totloop);
- blend[2] = divide_round_i(blend[2], totloop);
- blend[3] = divide_round_i(blend[3], totloop);
- col = (char *)&tcol;
- col[0] = blend[0];
- col[1] = blend[1];
- col[2] = blend[2];
- col[3] = blend[3];
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+ const float *sculpt_normal_frontface =
+ sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
- vpd->paintcol = *((unsigned int *)col);
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* Note: Grids are 1:1 with corners (aka loops).
+ * For grid based pbvh, take the vert whose loop cooresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
+ const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv = &data->me->mvert[v_index];
+
+ /* If the vertex is selected for painting. */
+ if (!use_vert_sel || mv->flag & SELECT) {
+ /* Calc the dot prod. between ray norm on surf and current vert
+ * (ie splash prevention factor), and only paint front facing verts. */
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
+ (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength)))
+ {
+ const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
+ uint color_final = data->vpd->paintcol;
+
+ /* If we're painting with a texture, sample the texture color and alpha. */
+ float tex_alpha = 1.0;
+ if (data->vpd->is_texbrush) {
+ /* Note: we may want to paint alpha as vertex color alpha. */
+ tex_alpha = tex_color_alpha_ubyte(
+ data, data->vpd->vertexcosnos[v_index].co,
+ &color_final);
+ }
+ /* For each poly owning this vert, paint each loop belonging to this vert. */
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ BLI_assert(data->me->mloop[l_index].v == v_index);
+ const MPoly *mp = &data->me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ uint color_orig = 0; /* unused when array is NULL */
+ if (ss->mode.vpaint.previous_color != NULL) {
+ /* Get the previous loop color */
+ if (ss->mode.vpaint.previous_color[l_index] == 0) {
+ ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
+ }
+ color_orig = ss->mode.vpaint.previous_color[l_index];
+ }
+ const float final_alpha =
+ 255 * brush_fade * brush_strength *
+ tex_alpha * brush_alpha_pressure * grid_alpha;
+
+ /* Mix the new color with the original based on final_alpha. */
+ lcol[l_index] = vpaint_blend(
+ data->vp, lcol[l_index], color_orig, color_final,
+ final_alpha, 255 * brush_strength);
+ }
+ }
+ }
+ }
+ }
}
+ BKE_pbvh_vertex_iter_end;
+}
- ml = me->mloop + mpoly->loopstart;
- for (i = 0; i < totloop; i++, ml++) {
- float rgba[4];
- unsigned int paintcol;
- alpha = calc_vp_alpha_col_dl(vp, vc, vpd->vpimat,
- &vpd->vertexcosnos[ml->v], mval,
- brush_size_pressure, brush_alpha_pressure, rgba);
+static void do_vpaint_brush_blur_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
+
+ Scene *scene = CTX_data_scene(data->C);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+ const Brush *brush = data->brush;
+ const StrokeCache *cache = ss->cache;
+ uint *lcol = data->lcol;
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- if (vpd->is_texbrush) {
- float rgba_br[3];
- rgb_uchar_to_float(rgba_br, (const unsigned char *)&vpd->paintcol);
- mul_v3_v3(rgba_br, rgba);
- rgb_float_to_uchar((unsigned char *)&paintcol, rgba_br);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+ const float *sculpt_normal_frontface =
+ sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* For grid based pbvh, take the vert whose loop cooresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
+ const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv = &data->me->mvert[v_index];
+
+ /* If the vertex is selected for painting. */
+ if (!use_vert_sel || mv->flag & SELECT) {
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
+ (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength)))
+ {
+ const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
+
+ /* Get the average poly color */
+ uint color_final = 0;
+ int total_hit_loops = 0;
+ uint blend[4] = {0};
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const MPoly *mp = &data->me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ total_hit_loops += mp->totloop;
+ for (int k = 0; k < mp->totloop; k++) {
+ const uint l_index = mp->loopstart + k;
+ const char *col = (const char *)(&lcol[l_index]);
+ /* Color is squared to compensate the sqrt color encoding. */
+ blend[0] += (uint)col[0] * (uint)col[0];
+ blend[1] += (uint)col[1] * (uint)col[1];
+ blend[2] += (uint)col[2] * (uint)col[2];
+ blend[3] += (uint)col[3] * (uint)col[3];
+ }
+ }
+ }
+ if (total_hit_loops != 0) {
+ /* Use rgb^2 color averaging. */
+ char *col = (char *)(&color_final);
+ col[0] = round_fl_to_uchar(sqrtf(divide_round_i(blend[0], total_hit_loops)));
+ col[1] = round_fl_to_uchar(sqrtf(divide_round_i(blend[1], total_hit_loops)));
+ col[2] = round_fl_to_uchar(sqrtf(divide_round_i(blend[2], total_hit_loops)));
+ col[3] = round_fl_to_uchar(sqrtf(divide_round_i(blend[3], total_hit_loops)));
+
+ /* For each poly owning this vert, paint each loop belonging to this vert. */
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ BLI_assert(data->me->mloop[l_index].v == v_index);
+ const MPoly *mp = &data->me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ uint color_orig = 0; /* unused when array is NULL */
+ if (ss->mode.vpaint.previous_color != NULL) {
+ /* Get the previous loop color */
+ if (ss->mode.vpaint.previous_color[l_index] == 0) {
+ ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
+ }
+ color_orig = ss->mode.vpaint.previous_color[l_index];
+ }
+ const float final_alpha =
+ 255 * brush_fade * brush_strength *
+ brush_alpha_pressure * grid_alpha;
+ /* Mix the new color with the original
+ * based on the brush strength and the curve. */
+ lcol[l_index] = vpaint_blend(
+ data->vp, lcol[l_index], color_orig, *((uint *)col),
+ final_alpha, 255 * brush_strength);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_vpaint_brush_smear_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
+
+ Scene *scene = CTX_data_scene(data->C);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+ const Brush *brush = data->brush;
+ const StrokeCache *cache = ss->cache;
+ uint *lcol = data->lcol;
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ float brush_dir[3];
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+ sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
+ project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
+
+ if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+ const float *sculpt_normal_frontface =
+ sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* For grid based pbvh, take the vert whose loop cooresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
+ const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv_curr = &data->me->mvert[v_index];
+
+ /* if the vertex is selected for painting. */
+ if (!use_vert_sel || mv_curr->flag & SELECT) {
+ /* Calc the dot prod. between ray norm on surf and current vert
+ * (ie splash prevention factor), and only paint front facing verts. */
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
+ (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength)))
+ {
+ const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
+
+ bool do_color = false;
+ /* Minimum dot product between brush direction and current
+ * to neighbor direction is 0.0, meaning orthogonal. */
+ float stroke_dot_max = 0.0f;
+
+ /* Get the color of the loop in the opposite direction of the brush movement */
+ uint color_final = 0;
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ BLI_assert(data->me->mloop[l_index].v == v_index);
+ UNUSED_VARS_NDEBUG(l_index);
+ const MPoly *mp = &data->me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ const MLoop *ml_other = &data->me->mloop[mp->loopstart];
+ for (int k = 0; k < mp->totloop; k++, ml_other++) {
+ const uint v_other_index = ml_other->v;
+ if (v_other_index != v_index) {
+ const MVert *mv_other = &data->me->mvert[v_other_index];
+
+ /* Get the direction from the selected vert to the neighbor. */
+ float other_dir[3];
+ sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
+ project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
+
+ normalize_v3(other_dir);
+
+ const float stroke_dot = dot_v3v3(other_dir, brush_dir);
+
+ if (stroke_dot > stroke_dot_max) {
+ stroke_dot_max = stroke_dot;
+ color_final = data->vpd->smear.color_prev[mp->loopstart + k];
+ do_color = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (do_color) {
+ const float final_alpha =
+ 255 * brush_fade * brush_strength *
+ brush_alpha_pressure * grid_alpha;
+
+ /* For each poly owning this vert, paint each loop belonging to this vert. */
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ BLI_assert(data->me->mloop[l_index].v == v_index);
+ const MPoly *mp = &data->me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ /* Get the previous loop color */
+ uint color_orig = 0; /* unused when array is NULL */
+ if (ss->mode.vpaint.previous_color != NULL) {
+ /* Get the previous loop color */
+ if (ss->mode.vpaint.previous_color[l_index] == 0) {
+ ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
+ }
+ color_orig = ss->mode.vpaint.previous_color[l_index];
+ }
+ /* Mix the new color with the original
+ * based on the brush strength and the curve. */
+ lcol[l_index] = vpaint_blend(
+ data->vp, lcol[l_index], color_orig, color_final,
+ final_alpha, 255 * brush_strength);
+
+ data->vpd->smear.color_curr[l_index] = lcol[l_index];
+ }
+ }
+ }
+ }
+ }
+ }
}
- else
- paintcol = vpd->paintcol;
+ BKE_pbvh_vertex_iter_end;
+ }
+}
- if (alpha > 0.0f) {
- const int alpha_i = (int)(alpha * 255.0f);
- lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], paintcol, alpha_i, brush_alpha_pressure_i);
+static void calculate_average_color(SculptThreadedTaskData *data, PBVHNode **UNUSED(nodes), int totnode)
+{
+ struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
+ data->custom_data = accum;
+
+ BLI_task_parallel_range_ex(
+ 0, totnode, data, NULL, 0, do_vpaint_brush_calc_average_color_cb_ex,
+ true, false);
+
+ uint accum_len = 0;
+ uint accum_value[3] = {0};
+ uchar blend[4] = {0};
+ for (int i = 0; i < totnode; i++) {
+ accum_len += accum[i].len;
+ accum_value[0] += accum[i].value[0];
+ accum_value[1] += accum[i].value[1];
+ accum_value[2] += accum[i].value[2];
+ }
+ if (accum_len != 0) {
+ blend[0] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[0], accum_len)));
+ blend[1] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[1], accum_len)));
+ blend[2] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[2], accum_len)));
+ blend[3] = 255;
+ data->vpd->paintcol = *((uint *)blend);
+ }
+
+ MEM_SAFE_FREE(data->custom_data); /* 'accum' */
+}
+
+static void vpaint_paint_leaves(
+ bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd,
+ Object *ob, Mesh *me, PBVHNode **nodes, int totnode)
+{
+ const Brush *brush = ob->sculpt->cache->brush;
+
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd,
+ .lcol = (uint *)me->mloopcol, .me = me, .C = C,
+ };
+ switch (brush->vertexpaint_tool) {
+ case PAINT_BLEND_AVERAGE:
+ calculate_average_color(&data, nodes, totnode);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0,
+ do_vpaint_brush_draw_task_cb_ex, true, false);
+ break;
+ case PAINT_BLEND_BLUR:
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0,
+ do_vpaint_brush_blur_task_cb_ex, true, false);
+ break;
+ case PAINT_BLEND_SMEAR:
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0,
+ do_vpaint_brush_smear_task_cb_ex, true, false);
+ break;
+ default:
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0,
+ do_vpaint_brush_draw_task_cb_ex, true, false);
+ break;
+ }
+}
+
+static void vpaint_do_paint(
+ bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd,
+ Object *ob, Mesh *me, Brush *brush, const char symm, const int axis, const int i, const float angle)
+{
+ SculptSession *ss = ob->sculpt;
+ ss->cache->radial_symmetry_pass = i;
+ sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
+
+ int totnode;
+ PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, vp, sd, brush, &totnode);
- if (mlooptag) mlooptag[i] = 1;
+ /* Paint those leaves. */
+ vpaint_paint_leaves(C, sd, vp, vpd, ob, me, nodes, totnode);
+
+ if (nodes) {
+ MEM_freeN(nodes);
+ }
+}
+
+static void vpaint_do_radial_symmetry(
+ bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd, Object *ob, Mesh *me,
+ Brush *brush, const char symm, const int axis)
+{
+ for (int i = 1; i < vp->radial_symm[axis - 'X']; i++) {
+ const float angle = (2.0 * M_PI) * i / vp->radial_symm[axis - 'X'];
+ vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, symm, axis, i, angle);
+ }
+}
+
+/* near duplicate of: sculpt.c's, 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */
+static void vpaint_do_symmetrical_brush_actions(
+ bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd, Object *ob)
+{
+ Brush *brush = BKE_paint_brush(&vp->paint);
+ Mesh *me = ob->data;
+ SculptSession *ss = ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ const char symm = vp->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ int i = 0;
+
+ /* initial stroke */
+ vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'X');
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Y');
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Z');
+
+ cache->symmetry = symm;
+
+ /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
+ for (i = 1; i <= symm; i++) {
+ if (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) {
+ cache->mirror_symmetry_pass = i;
+ cache->radial_symmetry_pass = 0;
+ sculpt_cache_calc_brushdata_symm(cache, i, 0, 0);
+
+ if (i & (1 << 0)) {
+ vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'X');
+ }
+ if (i & (1 << 1)) {
+ vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'Y', 0, 0);
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Y');
+ }
+ if (i & (1 << 2)) {
+ vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'Z', 0, 0);
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Z');
+ }
}
}
+
+ copy_v3_v3(cache->true_last_location, cache->true_location);
+ cache->is_last_valid = true;
}
static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
@@ -2795,63 +2917,28 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
ToolSettings *ts = CTX_data_tool_settings(C);
struct VPaintData *vpd = paint_stroke_mode_data(stroke);
VPaint *vp = ts->vpaint;
- Brush *brush = BKE_paint_brush(&vp->paint);
ViewContext *vc = &vpd->vc;
Object *ob = vc->obact;
- Mesh *me = ob->data;
- float mat[4][4];
- int *indexar = vpd->indexar;
- int totindex, index;
- float mval[2];
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- const float pressure = RNA_float_get(itemptr, "pressure");
- const float brush_size_pressure =
- BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f);
- const float brush_alpha_pressure =
- BKE_brush_alpha_get(scene, brush) * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f);
+ vwpaint_update_cache_variants(C, vp, ob, itemptr);
- RNA_float_get_array(itemptr, "mouse", mval);
+ float mat[4][4];
+ float mval[2];
- view3d_operator_needs_opengl(C);
ED_view3d_init_mats_rv3d(ob, vc->rv3d);
/* load projection matrix */
mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
- /* which faces are involved */
- totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure);
-
- if ((me->editflag & ME_EDIT_PAINT_FACE_SEL) && me->mpoly) {
- for (index = 0; index < totindex; index++) {
- if (indexar[index] && indexar[index] <= me->totpoly) {
- const MPoly *mpoly = &me->mpoly[indexar[index] - 1];
-
- if ((mpoly->flag & ME_FACE_SEL) == 0)
- indexar[index] = 0;
- }
- }
- }
-
swap_m4m4(vc->rv3d->persmat, mat);
- /* incase we have modifiers */
- ED_vpaint_proj_handle_update(vpd->vp_handle, vc->ar, mval);
-
- /* clear modified tag for blur tool */
- if (vpd->mlooptag)
- memset(vpd->mlooptag, 0, sizeof(bool) * me->totloop);
+ vpaint_do_symmetrical_brush_actions(C, sd, vp, vpd, ob);
- for (index = 0; index < totindex; index++) {
- if (indexar[index] && indexar[index] <= me->totpoly) {
- vpaint_paint_poly(vp, vpd, me, indexar[index] - 1, mval, brush_size_pressure, brush_alpha_pressure);
- }
- }
-
swap_m4m4(vc->rv3d->persmat, mat);
- /* was disabled because it is slow, but necessary for blur */
- if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
- do_shared_vertexcol(me, vpd->mlooptag);
+ if (vp->paint.brush->vertexpaint_tool == PAINT_BLEND_SMEAR) {
+ memcpy(vpd->smear.color_prev, vpd->smear.color_curr, sizeof(uint) * ((Mesh *)ob->data)->totloop);
}
/* calculate pivot for rotation around seletion if needed */
@@ -2873,35 +2960,38 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
struct VPaintData *vpd = paint_stroke_mode_data(stroke);
ViewContext *vc = &vpd->vc;
Object *ob = vc->obact;
- Mesh *me = ob->data;
- ED_vpaint_proj_handle_free(vpd->vp_handle);
- MEM_freeN(vpd->indexar);
-
- /* frees prev buffer */
- copy_vpaint_prev(ts->vpaint, NULL, 0);
+ if (vpd->is_texbrush) {
+ ED_vpaint_proj_handle_free(vpd->vp_handle);
+ }
if (vpd->mlooptag)
MEM_freeN(vpd->mlooptag);
+ if (vpd->smear.color_prev)
+ MEM_freeN(vpd->smear.color_prev);
+ if (vpd->smear.color_curr)
+ MEM_freeN(vpd->smear.color_curr);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- DAG_id_tag_update(&me->id, 0);
MEM_freeN(vpd);
+
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
}
static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
- op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start,
- vpaint_stroke_update_step, NULL,
- vpaint_stroke_done, event->type);
-
+ op->customdata = paint_stroke_new(
+ C, op, sculpt_stroke_get_location, vpaint_stroke_test_start,
+ vpaint_stroke_update_step, NULL,
+ vpaint_stroke_done, event->type);
+
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
paint_stroke_data_free(op);
return OPERATOR_FINISHED;
@@ -2912,15 +3002,16 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
OPERATOR_RETVAL_CHECK(retval);
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
-
+
return OPERATOR_RUNNING_MODAL;
}
static int vpaint_exec(bContext *C, wmOperator *op)
{
- op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start,
- vpaint_stroke_update_step, NULL,
- vpaint_stroke_done, 0);
+ op->customdata = paint_stroke_new(
+ C, op, sculpt_stroke_get_location, vpaint_stroke_test_start,
+ vpaint_stroke_update_step, NULL,
+ vpaint_stroke_done, 0);
/* frees op->customdata */
paint_stroke_exec(C, op);
@@ -2930,6 +3021,12 @@ static int vpaint_exec(bContext *C, wmOperator *op)
static void vpaint_cancel(bContext *C, wmOperator *op)
{
+ Object *ob = CTX_data_active_object(C);
+ if (ob->sculpt->cache) {
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
+ }
+
paint_stroke_cancel(C, op);
}
@@ -2939,382 +3036,16 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot)
ot->name = "Vertex Paint";
ot->idname = "PAINT_OT_vertex_paint";
ot->description = "Paint a stroke in the active vertex color layer";
-
+
/* api callbacks */
ot->invoke = vpaint_invoke;
ot->modal = paint_stroke_modal;
ot->exec = vpaint_exec;
ot->poll = vertex_paint_poll;
ot->cancel = vpaint_cancel;
-
+
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
paint_stroke_operator_properties(ot);
}
-
-/* ********************** weight from bones operator ******************* */
-
-static int weight_from_bones_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
-
- return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob));
-}
-
-static int weight_from_bones_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Object *armob = modifiers_isDeformedByArmature(ob);
- Mesh *me = ob->data;
- int type = RNA_enum_get(op->ptr, "type");
-
- create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X));
-
- DAG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
-
- return OPERATOR_FINISHED;
-}
-
-void PAINT_OT_weight_from_bones(wmOperatorType *ot)
-{
- static EnumPropertyItem type_items[] = {
- {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"},
- {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"},
- {0, NULL, 0, NULL, NULL}};
-
- /* identifiers */
- ot->name = "Weight from Bones";
- ot->idname = "PAINT_OT_weight_from_bones";
- ot->description = "Set the weights of the groups matching the attached armature's selected bones, "
- "using the distance between the vertices and the bones";
-
- /* api callbacks */
- ot->exec = weight_from_bones_exec;
- ot->invoke = WM_menu_invoke;
- ot->poll = weight_from_bones_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights");
-}
-
-/* *** VGroups Gradient *** */
-typedef struct DMGradient_vertStore {
- float sco[2];
- float weight_orig;
- enum {
- VGRAD_STORE_NOP = 0,
- VGRAD_STORE_DW_EXIST = (1 << 0)
- } flag;
-} DMGradient_vertStore;
-
-typedef struct DMGradient_userData {
- struct ARegion *ar;
- Scene *scene;
- Mesh *me;
- Brush *brush;
- const float *sco_start; /* [2] */
- const float *sco_end; /* [2] */
- float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */
- int def_nr;
- bool is_init;
- DMGradient_vertStore *vert_cache;
- /* only for init */
- BLI_bitmap *vert_visit;
-
- /* options */
- short use_select;
- short type;
- float weightpaint;
-} DMGradient_userData;
-
-static void gradientVert_update(DMGradient_userData *grad_data, int index)
-{
- Mesh *me = grad_data->me;
- DMGradient_vertStore *vs = &grad_data->vert_cache[index];
- float alpha;
-
- if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
- alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end);
- }
- else {
- BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL);
- alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
- }
- /* no need to clamp 'alpha' yet */
-
- /* adjust weight */
- alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f);
-
- if (alpha != 0.0f) {
- MDeformVert *dv = &me->dvert[index];
- MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr);
- // dw->weight = alpha; // testing
- int tool = grad_data->brush->vertexpaint_tool;
- float testw;
-
- /* init if we just added */
- testw = wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha);
- CLAMP(testw, 0.0f, 1.0f);
- dw->weight = testw;
- }
- else {
- MDeformVert *dv = &me->dvert[index];
- if (vs->flag & VGRAD_STORE_DW_EXIST) {
- /* normally we NULL check, but in this case we know it exists */
- MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
- dw->weight = vs->weight_orig;
- }
- else {
- /* wasn't originally existing, remove */
- MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
- if (dw) {
- defvert_remove_group(dv, dw);
- }
- }
- }
-}
-
-static void gradientVertUpdate__mapFunc(
- void *userData, int index, const float UNUSED(co[3]),
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
-{
- DMGradient_userData *grad_data = userData;
- Mesh *me = grad_data->me;
- if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) {
- DMGradient_vertStore *vs = &grad_data->vert_cache[index];
- if (vs->sco[0] != FLT_MAX) {
- gradientVert_update(grad_data, index);
- }
- }
-}
-
-static void gradientVertInit__mapFunc(
- void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
-{
- DMGradient_userData *grad_data = userData;
- Mesh *me = grad_data->me;
-
- if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) {
- /* run first pass only,
- * the screen coords of the verts need to be cached because
- * updating the mesh may move them about (entering feedback loop) */
-
- if (BLI_BITMAP_TEST(grad_data->vert_visit, index) == 0) {
- DMGradient_vertStore *vs = &grad_data->vert_cache[index];
- if (ED_view3d_project_float_object(grad_data->ar,
- co, vs->sco,
- V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
- {
- /* ok */
- MDeformVert *dv = &me->dvert[index];
- MDeformWeight *dw;
- dw = defvert_find_index(dv, grad_data->def_nr);
- if (dw) {
- vs->weight_orig = dw->weight;
- vs->flag = VGRAD_STORE_DW_EXIST;
- }
- else {
- vs->weight_orig = 0.0f;
- vs->flag = VGRAD_STORE_NOP;
- }
-
- BLI_BITMAP_ENABLE(grad_data->vert_visit, index);
-
- gradientVert_update(grad_data, index);
- }
- else {
- /* no go */
- copy_v2_fl(vs->sco, FLT_MAX);
- }
- }
- }
-}
-
-static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- int ret = WM_gesture_straightline_modal(C, op, event);
-
- if (ret & OPERATOR_RUNNING_MODAL) {
- if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */
- /* generally crap! redo! */
- WM_gesture_straightline_cancel(C, op);
- ret &= ~OPERATOR_RUNNING_MODAL;
- ret |= OPERATOR_FINISHED;
- }
- }
-
- if (ret & OPERATOR_CANCELLED) {
- ToolSettings *ts = CTX_data_tool_settings(C);
- VPaint *wp = ts->wpaint;
- Object *ob = CTX_data_active_object(C);
- Mesh *me = ob->data;
- if (wp->wpaint_prev) {
- BKE_defvert_array_free_elems(me->dvert, me->totvert);
- BKE_defvert_array_copy(me->dvert, wp->wpaint_prev, me->totvert);
- free_wpaint_prev(wp);
- }
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- }
- else if (ret & OPERATOR_FINISHED) {
- ToolSettings *ts = CTX_data_tool_settings(C);
- VPaint *wp = ts->wpaint;
- free_wpaint_prev(wp);
- }
-
- return ret;
-}
-
-static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
-{
- wmGesture *gesture = op->customdata;
- DMGradient_vertStore *vert_cache;
- struct ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Mesh *me = ob->data;
- int x_start = RNA_int_get(op->ptr, "xstart");
- int y_start = RNA_int_get(op->ptr, "ystart");
- int x_end = RNA_int_get(op->ptr, "xend");
- int y_end = RNA_int_get(op->ptr, "yend");
- float sco_start[2] = {x_start, y_start};
- float sco_end[2] = {x_end, y_end};
- const bool is_interactive = (gesture != NULL);
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
-
- DMGradient_userData data = {NULL};
-
- if (is_interactive) {
- if (gesture->userdata == NULL) {
- VPaint *wp = scene->toolsettings->wpaint;
-
- gesture->userdata = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__);
- data.is_init = true;
-
- copy_wpaint_prev(wp, me->dvert, me->totvert);
-
- /* on init only, convert face -> vert sel */
- if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
- BKE_mesh_flush_select_from_polys(me);
- }
- }
-
- vert_cache = gesture->userdata;
- }
- else {
- if (wpaint_ensure_data(C, op, 0, NULL) == false) {
- return OPERATOR_CANCELLED;
- }
-
- data.is_init = true;
- vert_cache = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__);
- }
-
- data.ar = ar;
- data.scene = scene;
- data.me = ob->data;
- data.sco_start = sco_start;
- data.sco_end = sco_end;
- data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
- data.def_nr = ob->actdef - 1;
- data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL));
- data.vert_cache = vert_cache;
- data.vert_visit = NULL;
- data.type = RNA_enum_get(op->ptr, "type");
-
- {
- ToolSettings *ts = CTX_data_tool_settings(C);
- VPaint *wp = ts->wpaint;
- struct Brush *brush = BKE_paint_brush(&wp->paint);
-
- curvemapping_initialize(brush->curve);
-
- data.brush = brush;
- data.weightpaint = BKE_brush_weight_get(scene, brush);
- }
-
- ED_view3d_init_mats_rv3d(ob, ar->regiondata);
-
- if (data.is_init) {
- data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__);
-
- dm->foreachMappedVert(dm, gradientVertInit__mapFunc, &data, DM_FOREACH_NOP);
-
- MEM_freeN(data.vert_visit);
- data.vert_visit = NULL;
- }
- else {
- dm->foreachMappedVert(dm, gradientVertUpdate__mapFunc, &data, DM_FOREACH_NOP);
- }
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- if (is_interactive == false) {
- MEM_freeN(vert_cache);
- }
-
- return OPERATOR_FINISHED;
-}
-
-static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- int ret;
-
- if (wpaint_ensure_data(C, op, 0, NULL) == false) {
- return OPERATOR_CANCELLED;
- }
-
- ret = WM_gesture_straightline_invoke(C, op, event);
- if (ret & OPERATOR_RUNNING_MODAL) {
- struct ARegion *ar = CTX_wm_region(C);
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- /* TODO, hardcoded, extend WM_gesture_straightline_ */
- if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
- wmGesture *gesture = op->customdata;
- gesture->mode = 1;
- }
- }
- }
- return ret;
-}
-
-void PAINT_OT_weight_gradient(wmOperatorType *ot)
-{
- /* defined in DNA_space_types.h */
- static EnumPropertyItem gradient_types[] = {
- {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""},
- {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Weight Gradient";
- ot->idname = "PAINT_OT_weight_gradient";
- ot->description = "Draw a line to apply a weight gradient to selected vertices";
-
- /* api callbacks */
- ot->invoke = paint_weight_gradient_invoke;
- ot->modal = paint_weight_gradient_modal;
- ot->exec = paint_weight_gradient_exec;
- ot->poll = weight_paint_poll;
- ot->cancel = WM_gesture_straightline_cancel;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
-}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
new file mode 100644
index 00000000000..b69ca32e5af
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -0,0 +1,574 @@
+/*
+ * ***** 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/sculpt_paint/paint_vertex_color_ops.c
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_math_base.h"
+#include "BLI_math_color.h"
+
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_mesh.h"
+#include "BKE_deform.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+
+#include "paint_intern.h" /* own include */
+
+
+static int vertex_weight_paint_mode_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = BKE_mesh_from_object(ob);
+ return (ob && (ob->mode == OB_MODE_VERTEX_PAINT || ob->mode == OB_MODE_WEIGHT_PAINT)) &&
+ (me && me->totpoly && me->dvert);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Set Vertex Colors Operator
+ * \{ */
+
+static bool vertex_color_set(Object *ob, uint paintcol)
+{
+ Mesh *me;
+ const MPoly *mp;
+ int i, j;
+
+ if (((me = BKE_mesh_from_object(ob)) == NULL) ||
+ (ED_mesh_color_ensure(me, NULL) == false))
+ {
+ return false;
+ }
+
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+
+ mp = me->mpoly;
+ for (i = 0; i < me->totpoly; i++, mp++) {
+ MLoopCol *lcol = me->mloopcol + mp->loopstart;
+
+ if (use_face_sel && !(mp->flag & ME_FACE_SEL))
+ continue;
+
+ j = 0;
+ do {
+ uint vidx = me->mloop[mp->loopstart + j].v;
+ if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
+ *(int *)lcol = paintcol;
+ }
+ lcol++;
+ j++;
+ } while (j < mp->totloop);
+
+ }
+
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
+
+ DAG_id_tag_update(&me->id, 0);
+
+ return true;
+}
+
+static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obact = CTX_data_active_object(C);
+ unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint);
+
+ if (vertex_color_set(obact, paintcol)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void PAINT_OT_vertex_color_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Vertex Colors";
+ ot->idname = "PAINT_OT_vertex_color_set";
+ ot->description = "Fill the active vertex color layer with the current paint color";
+
+ /* api callbacks */
+ ot->exec = vertex_color_set_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex Color from Weight Operator
+ * \{ */
+
+static bool vertex_paint_from_weight(Object *ob)
+{
+ Mesh *me;
+ const MPoly *mp;
+ int vgroup_active;
+
+ if (((me = BKE_mesh_from_object(ob)) == NULL ||
+ (ED_mesh_color_ensure(me, NULL)) == false))
+ {
+ return false;
+ }
+
+ /* TODO: respect selection. */
+ mp = me->mpoly;
+ vgroup_active = ob->actdef - 1;
+ for (int i = 0; i < me->totpoly; i++, mp++) {
+ MLoopCol *lcol = &me->mloopcol[mp->loopstart];
+ uint j = 0;
+ do {
+ uint vidx = me->mloop[mp->loopstart + j].v;
+ const float weight = defvert_find_weight(&me->dvert[vidx], vgroup_active);
+ const uchar grayscale = weight * 255;
+ lcol->r = grayscale;
+ lcol->b = grayscale;
+ lcol->g = grayscale;
+ lcol++;
+ j++;
+ } while (j < mp->totloop);
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ return true;
+}
+
+static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obact = CTX_data_active_object(C);
+ if (vertex_paint_from_weight(obact)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Color from Weight";
+ ot->idname = "PAINT_OT_vertex_color_from_weight";
+ ot->description = "Convert active weight into gray scale vertex colors";
+
+ /* api callback */
+ ot->exec = vertex_paint_from_weight_exec;
+ ot->poll = vertex_weight_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* TODO: invert, alpha */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Vertex Colors Operator
+ * \{ */
+
+static void vertex_color_smooth_looptag(Mesh *me, bool *mlooptag)
+{
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const MPoly *mp;
+ int (*scol)[4];
+ int i, j;
+ bool has_shared = false;
+
+ /* if no mloopcol: do not do */
+ /* if mtexpoly: only the involved faces, otherwise all */
+
+ if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return;
+
+ scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol");
+
+ for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
+ if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
+ const MLoop *ml = me->mloop + mp->loopstart;
+ MLoopCol *lcol = me->mloopcol + mp->loopstart;
+ for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
+ scol[ml->v][0] += lcol->r;
+ scol[ml->v][1] += lcol->g;
+ scol[ml->v][2] += lcol->b;
+ scol[ml->v][3] += 1;
+ has_shared = 1;
+ }
+ }
+ }
+
+ if (has_shared) {
+ for (i = 0; i < me->totvert; i++) {
+ if (scol[i][3] != 0) {
+ scol[i][0] = divide_round_i(scol[i][0], scol[i][3]);
+ scol[i][1] = divide_round_i(scol[i][1], scol[i][3]);
+ scol[i][2] = divide_round_i(scol[i][2], scol[i][3]);
+ }
+ }
+
+ for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
+ if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
+ const MLoop *ml = me->mloop + mp->loopstart;
+ MLoopCol *lcol = me->mloopcol + mp->loopstart;
+ for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
+ if (mlooptag[mp->loopstart + j]) {
+ lcol->r = scol[ml->v][0];
+ lcol->g = scol[ml->v][1];
+ lcol->b = scol[ml->v][2];
+ }
+ }
+ }
+ }
+ }
+
+ MEM_freeN(scol);
+}
+
+static bool vertex_color_smooth(Object *ob)
+{
+ Mesh *me;
+ const MPoly *mp;
+
+ int i, j;
+
+ bool *mlooptag;
+
+ if (((me = BKE_mesh_from_object(ob)) == NULL) ||
+ (ED_mesh_color_ensure(me, NULL) == false))
+ {
+ return false;
+ }
+
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+ mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
+
+ /* simply tag loops of selected faces */
+ mp = me->mpoly;
+ for (i = 0; i < me->totpoly; i++, mp++) {
+ const MLoop *ml = me->mloop + mp->loopstart;
+ int ml_index = mp->loopstart;
+
+ if (use_face_sel && !(mp->flag & ME_FACE_SEL))
+ continue;
+
+ for (j = 0; j < mp->totloop; j++, ml_index++, ml++) {
+ mlooptag[ml_index] = true;
+ }
+ }
+
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
+
+ vertex_color_smooth_looptag(me, mlooptag);
+
+ MEM_freeN(mlooptag);
+
+ DAG_id_tag_update(&me->id, 0);
+
+ return true;
+}
+
+
+static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obact = CTX_data_active_object(C);
+ if (vertex_color_smooth(obact)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Smooth Vertex Colors";
+ ot->idname = "PAINT_OT_vertex_color_smooth";
+ ot->description = "Smooth colors across vertices";
+
+ /* api callbacks */
+ ot->exec = vertex_color_smooth_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex Color Transformation Operators
+ * \{ */
+
+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)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+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)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+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)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+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)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+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);
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
new file mode 100644
index 00000000000..398512287c4
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
@@ -0,0 +1,648 @@
+/*
+ * ***** 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/sculpt_paint/paint_vertex_color_utils.c
+ * \ingroup edsculpt
+ *
+ * Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_math_base.h"
+#include "BLI_math_color.h"
+
+#include "IMB_colormanagement.h"
+
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_mesh.h"
+
+#include "ED_mesh.h"
+
+#include "paint_intern.h" /* own include */
+
+#define EPS_SATURATION 0.0005f
+
+/**
+ * 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) ||
+ (ED_mesh_color_ensure(me, NULL) == false))
+ {
+ return false;
+ }
+
+ const bool use_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 (use_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;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Color Blending Modes
+ * \{ */
+
+BLI_INLINE uint mcol_blend(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ if (fac >= 255) {
+ return col2;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ /* Updated to use the rgb squared color model which blends nicer. */
+ int r1 = cp1[0] * cp1[0];
+ int g1 = cp1[1] * cp1[1];
+ int b1 = cp1[2] * cp1[2];
+ int a1 = cp1[3] * cp1[3];
+
+ int r2 = cp2[0] * cp2[0];
+ int g2 = cp2[1] * cp2[1];
+ int b2 = cp2[2] * cp2[2];
+ int a2 = cp2[3] * cp2[3];
+
+ cp[0] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * r1 + fac * r2), 255)));
+ cp[1] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * g1 + fac * g2), 255)));
+ cp[2] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * b1 + fac * b2), 255)));
+ cp[3] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * a1 + fac * a2), 255)));
+
+ return col;
+}
+
+BLI_INLINE uint mcol_add(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int temp;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ temp = cp1[0] + divide_round_i((fac * cp2[0]), 255);
+ cp[0] = (temp > 254) ? 255 : temp;
+ temp = cp1[1] + divide_round_i((fac * cp2[1]), 255);
+ cp[1] = (temp > 254) ? 255 : temp;
+ temp = cp1[2] + divide_round_i((fac * cp2[2]), 255);
+ cp[2] = (temp > 254) ? 255 : temp;
+ temp = cp1[3] + divide_round_i((fac * cp2[3]), 255);
+ cp[3] = (temp > 254) ? 255 : temp;
+
+ return col;
+}
+
+BLI_INLINE uint mcol_sub(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int temp;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ temp = cp1[0] - divide_round_i((fac * cp2[0]), 255);
+ cp[0] = (temp < 0) ? 0 : temp;
+ temp = cp1[1] - divide_round_i((fac * cp2[1]), 255);
+ cp[1] = (temp < 0) ? 0 : temp;
+ temp = cp1[2] - divide_round_i((fac * cp2[2]), 255);
+ cp[2] = (temp < 0) ? 0 : temp;
+ temp = cp1[3] - divide_round_i((fac * cp2[3]), 255);
+ cp[3] = (temp < 0) ? 0 : temp;
+
+ return col;
+}
+
+BLI_INLINE uint mcol_mul(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ /* first mul, then blend the fac */
+ cp[0] = divide_round_i(mfac * cp1[0] * 255 + fac * cp2[0] * cp1[0], 255 * 255);
+ cp[1] = divide_round_i(mfac * cp1[1] * 255 + fac * cp2[1] * cp1[1], 255 * 255);
+ cp[2] = divide_round_i(mfac * cp1[2] * 255 + fac * cp2[2] * cp1[2], 255 * 255);
+ cp[3] = divide_round_i(mfac * cp1[3] * 255 + fac * cp2[3] * cp1[3], 255 * 255);
+
+ return col;
+}
+
+BLI_INLINE uint mcol_lighten(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+ else if (fac >= 255) {
+ return col2;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ /* See if are lighter, if so mix, else don't do anything.
+ * if the paint col is darker then the original, then ignore */
+ if (IMB_colormanagement_get_luminance_byte(cp1) > IMB_colormanagement_get_luminance_byte(cp2)) {
+ return col1;
+ }
+
+ cp[0] = divide_round_i(mfac * cp1[0] + fac * cp2[0], 255);
+ cp[1] = divide_round_i(mfac * cp1[1] + fac * cp2[1], 255);
+ cp[2] = divide_round_i(mfac * cp1[2] + fac * cp2[2], 255);
+ cp[3] = divide_round_i(mfac * cp1[3] + fac * cp2[3], 255);
+
+ return col;
+}
+
+BLI_INLINE uint mcol_darken(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+ else if (fac >= 255) {
+ return col2;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ /* See if were darker, if so mix, else don't do anything.
+ * if the paint col is brighter then the original, then ignore */
+ if (IMB_colormanagement_get_luminance_byte(cp1) < IMB_colormanagement_get_luminance_byte(cp2)) {
+ return col1;
+ }
+
+ cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255);
+ cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255);
+ cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255);
+ cp[3] = divide_round_i((mfac * cp1[3] + fac * cp2[3]), 255);
+ return col;
+}
+
+BLI_INLINE uint mcol_colordodge(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac, temp;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ temp = (cp2[0] == 255) ? 255 : min_ii((cp1[0] * 225) / (255 - cp2[0]), 255);
+ cp[0] = (mfac * cp1[0] + temp * fac) / 255;
+ temp = (cp2[1] == 255) ? 255 : min_ii((cp1[1] * 225) / (255 - cp2[1]), 255);
+ cp[1] = (mfac * cp1[1] + temp * fac) / 255;
+ temp = (cp2[2] == 255) ? 255 : min_ii((cp1[2] * 225) / (255 - cp2[2]), 255);
+ cp[2] = (mfac * cp1[2] + temp * fac) / 255;
+ temp = (cp2[3] == 255) ? 255 : min_ii((cp1[3] * 225) / (255 - cp2[3]), 255);
+ cp[3] = (mfac * cp1[3] + temp * fac) / 255;
+ return col;
+}
+
+BLI_INLINE uint mcol_difference(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac, temp;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ temp = abs(cp1[0] - cp2[0]);
+ cp[0] = (mfac * cp1[0] + temp * fac) / 255;
+ temp = abs(cp1[1] - cp2[1]);
+ cp[1] = (mfac * cp1[1] + temp * fac) / 255;
+ temp = abs(cp1[2] - cp2[2]);
+ cp[2] = (mfac * cp1[2] + temp * fac) / 255;
+ temp = abs(cp1[3] - cp2[3]);
+ cp[3] = (mfac * cp1[3] + temp * fac) / 255;
+ return col;
+}
+
+BLI_INLINE uint mcol_screen(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac, temp;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ temp = max_ii(255 - (((255 - cp1[0]) * (255 - cp2[0])) / 255), 0);
+ cp[0] = (mfac * cp1[0] + temp * fac) / 255;
+ temp = max_ii(255 - (((255 - cp1[1]) * (255 - cp2[1])) / 255), 0);
+ cp[1] = (mfac * cp1[1] + temp * fac) / 255;
+ temp = max_ii(255 - (((255 - cp1[2]) * (255 - cp2[2])) / 255), 0);
+ cp[2] = (mfac * cp1[2] + temp * fac) / 255;
+ temp = max_ii(255 - (((255 - cp1[3]) * (255 - cp2[3])) / 255), 0);
+ cp[3] = (mfac * cp1[3] + temp * fac) / 255;
+ return col;
+}
+
+BLI_INLINE uint mcol_hardlight(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac, temp;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (cp2[i] > 127) {
+ temp = 255 - ((255 - 2 * (cp2[i] - 127)) * (255 - cp1[i]) / 255);
+ }
+ else {
+ temp = (2 * cp2[i] * cp1[i]) >> 8;
+ }
+ cp[i] = min_ii((mfac * cp1[i] + temp * fac) / 255, 255);
+ }
+ return col;
+}
+
+BLI_INLINE uint mcol_overlay(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac, temp;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (cp1[i] > 127) {
+ temp = 255 - ((255 - 2 * (cp1[i] - 127)) * (255 - cp2[i]) / 255);
+ }
+ else {
+ temp = (2 * cp2[i] * cp1[i]) >> 8;
+ }
+ cp[i] = min_ii((mfac * cp1[i] + temp * fac) / 255, 255);
+ }
+ return col;
+}
+
+BLI_INLINE uint mcol_softlight(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac, temp;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (cp1[i] < 127) {
+ temp = ((2 * ((cp2[i] / 2) + 64)) * cp1[i]) / 255;
+ }
+ else {
+ temp = 255 - (2 * (255 - ((cp2[i] / 2) + 64)) * (255 - cp1[i]) / 255);
+ }
+ cp[i] = (temp * fac + cp1[i] * mfac) / 255;
+ }
+ return col;
+}
+
+BLI_INLINE uint mcol_exclusion(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac, temp;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ temp = 127 - ((2 * (cp1[i] - 127) * (cp2[i] - 127)) / 255);
+ cp[i] = (temp * fac + cp1[i] * mfac) / 255;
+ }
+ return col;
+}
+
+BLI_INLINE uint mcol_luminosity(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1);
+ rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2);
+
+ v1 = v2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255;
+ cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255;
+ cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255;
+ cp[3] = ((int)(cp2[3]) * fac + mfac * cp1[3]) / 255;
+ return col;
+}
+
+BLI_INLINE uint mcol_saturation(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1);
+ rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2);
+
+ if (s1 > EPS_SATURATION) {
+ s1 = s2;
+ }
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255;
+ cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255;
+ cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255;
+ return col;
+}
+
+BLI_INLINE uint mcol_hue(uint col1, uint col2, int fac)
+{
+ uchar *cp1, *cp2, *cp;
+ int mfac;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ mfac = 255 - fac;
+
+ cp1 = (uchar *)&col1;
+ cp2 = (uchar *)&col2;
+ cp = (uchar *)&col;
+
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1);
+ rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2);
+
+ h1 = h2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255;
+ cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255;
+ cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255;
+ cp[3] = ((int)(cp2[3]) * fac + mfac * cp1[3]) / 255;
+ return col;
+}
+
+BLI_INLINE uint mcol_alpha_add(uint col1, int fac)
+{
+ uchar *cp1, *cp;
+ int temp;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ cp1 = (uchar *)&col1;
+ cp = (uchar *)&col;
+
+ temp = cp1[3] + fac;
+ cp[3] = (temp > 254) ? 255 : temp;
+
+ return col;
+}
+
+BLI_INLINE uint mcol_alpha_sub(uint col1, int fac)
+{
+ uchar *cp1, *cp;
+ int temp;
+ uint col = 0;
+
+ if (fac == 0) {
+ return col1;
+ }
+
+ cp1 = (uchar *)&col1;
+ cp = (uchar *)&col;
+
+ temp = cp1[3] - fac;
+ cp[3] = temp < 0 ? 0 : temp;
+
+ return col;
+}
+
+/* wpaint has 'ED_wpaint_blend_tool' */
+uint ED_vpaint_blend_tool(
+ const int tool, const uint col,
+ const uint paintcol, const int alpha_i)
+{
+ switch (tool) {
+ case PAINT_BLEND_MIX:
+ case PAINT_BLEND_BLUR: return mcol_blend(col, paintcol, alpha_i);
+ case PAINT_BLEND_AVERAGE: return mcol_blend(col, paintcol, alpha_i);
+ case PAINT_BLEND_SMEAR: return mcol_blend(col, paintcol, alpha_i);
+ case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i);
+ case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i);
+ case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i);
+ case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i);
+ case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i);
+ case PAINT_BLEND_COLORDODGE: return mcol_colordodge(col, paintcol, alpha_i);
+ case PAINT_BLEND_DIFFERENCE: return mcol_difference(col, paintcol, alpha_i);
+ case PAINT_BLEND_SCREEN: return mcol_screen(col, paintcol, alpha_i);
+ case PAINT_BLEND_HARDLIGHT: return mcol_hardlight(col, paintcol, alpha_i);
+ case PAINT_BLEND_OVERLAY: return mcol_overlay(col, paintcol, alpha_i);
+ case PAINT_BLEND_SOFTLIGHT: return mcol_softlight(col, paintcol, alpha_i);
+ case PAINT_BLEND_EXCLUSION: return mcol_exclusion(col, paintcol, alpha_i);
+ case PAINT_BLEND_LUMINOCITY: return mcol_luminosity(col, paintcol, alpha_i);
+ case PAINT_BLEND_SATURATION: return mcol_saturation(col, paintcol, alpha_i);
+ case PAINT_BLEND_HUE: return mcol_hue(col, paintcol, alpha_i);
+ /* non-color */
+ case PAINT_BLEND_ALPHA_SUB: return mcol_alpha_sub(col, alpha_i);
+ case PAINT_BLEND_ALPHA_ADD: return mcol_alpha_add(col, alpha_i);
+ default:
+ BLI_assert(0);
+ return 0;
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
new file mode 100644
index 00000000000..9483a12aa6a
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -0,0 +1,859 @@
+/*
+ * ***** 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/sculpt_paint/paint_vertex_weight_ops.c
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_array_utils.h"
+#include "BLI_bitmap.h"
+#include "BLI_task.h"
+#include "BLI_string_utils.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_colormanagement.h"
+
+//#include "DNA_armature_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_deform.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_modifier.h"
+#include "BKE_object_deform.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+#include "BKE_colortools.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "paint_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name Store Previous Weights
+ *
+ * Use to avoid feedback loop w/ mirrored edits.
+ * \{ */
+
+struct WPaintPrev {
+ /* previous vertex weights */
+ struct MDeformVert *wpaint_prev;
+ /* allocation size of prev buffers */
+ int tot;
+};
+
+
+static void wpaint_prev_init(struct WPaintPrev *wpp)
+{
+ wpp->wpaint_prev = NULL;
+ wpp->tot = 0;
+}
+
+static void wpaint_prev_create(struct WPaintPrev *wpp, MDeformVert *dverts, int dcount)
+{
+ wpaint_prev_init(wpp);
+
+ if (dverts && dcount) {
+ wpp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev");
+ wpp->tot = dcount;
+ BKE_defvert_array_copy(wpp->wpaint_prev, dverts, dcount);
+ }
+}
+
+static void wpaint_prev_destroy(struct WPaintPrev *wpp)
+{
+ if (wpp->wpaint_prev) {
+ BKE_defvert_array_free(wpp->wpaint_prev, wpp->tot);
+ }
+ wpp->wpaint_prev = NULL;
+ wpp->tot = 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weight from Bones Operator
+ * \{ */
+
+static int weight_from_bones_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob));
+}
+
+static int weight_from_bones_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Object *armob = modifiers_isDeformedByArmature(ob);
+ Mesh *me = ob->data;
+ int type = RNA_enum_get(op->ptr, "type");
+
+ create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X));
+
+ DAG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_weight_from_bones(wmOperatorType *ot)
+{
+ static EnumPropertyItem type_items[] = {
+ {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"},
+ {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name = "Weight from Bones";
+ ot->idname = "PAINT_OT_weight_from_bones";
+ ot->description = "Set the weights of the groups matching the attached armature's selected bones, "
+ "using the distance between the vertices and the bones";
+
+ /* api callbacks */
+ ot->exec = weight_from_bones_exec;
+ ot->invoke = WM_menu_invoke;
+ ot->poll = weight_from_bones_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Weight Operator
+ * \{ */
+
+/* sets wp->weight to the closest weight value to vertex */
+/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
+static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ViewContext vc;
+ Mesh *me;
+ bool changed = false;
+
+ view3d_set_viewcontext(C, &vc);
+ me = BKE_mesh_from_object(vc.obact);
+
+ if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) {
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ int v_idx_best = -1;
+ uint index;
+
+ view3d_operator_needs_opengl(C);
+ ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
+
+ if (use_vert_sel) {
+ if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) {
+ v_idx_best = index;
+ }
+ }
+ else {
+ if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
+ v_idx_best = index;
+ }
+ else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
+ /* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */
+ BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
+ }
+ }
+
+ if (v_idx_best != -1) { /* should always be valid */
+ ToolSettings *ts = vc.scene->toolsettings;
+ Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
+ const int vgroup_active = vc.obact->actdef - 1;
+ float vgroup_weight = defvert_find_weight(&me->dvert[v_idx_best], vgroup_active);
+
+ /* use combined weight in multipaint mode, since that's what is displayed to the user in the colors */
+ if (ts->multipaint) {
+ int defbase_tot_sel;
+ const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
+ bool *defbase_sel = BKE_object_defgroup_selected_get(vc.obact, defbase_tot, &defbase_tot_sel);
+
+ if (defbase_tot_sel > 1) {
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ BKE_object_defgroup_mirror_selection(
+ vc.obact, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
+ }
+
+ vgroup_weight = BKE_defvert_multipaint_collective_weight(
+ &me->dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, ts->auto_normalize);
+
+ /* if autonormalize is enabled, but weights are not normalized, the value can exceed 1 */
+ CLAMP(vgroup_weight, 0.0f, 1.0f);
+ }
+
+ MEM_freeN(defbase_sel);
+ }
+
+ BKE_brush_weight_set(vc.scene, brush, vgroup_weight);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ /* not really correct since the brush didnt change, but redraws the toolbar */
+ WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); /* ts->wpaint->paint.brush */
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void PAINT_OT_weight_sample(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Weight Paint Sample Weight";
+ ot->idname = "PAINT_OT_weight_sample";
+ ot->description = "Use the mouse to sample a weight in the 3D view";
+
+ /* api callbacks */
+ ot->invoke = weight_sample_invoke;
+ ot->poll = weight_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weight Paint Sample Group Operator
+ * \{ */
+
+/* samples cursor location, and gives menu with vertex groups to activate */
+static bool weight_paint_sample_enum_itemf__helper(const MDeformVert *dvert, const int defbase_tot, int *groups)
+{
+ /* this func fills in used vgroup's */
+ bool found = false;
+ int i = dvert->totweight;
+ MDeformWeight *dw;
+ for (dw = dvert->dw; i > 0; dw++, i--) {
+ if (dw->def_nr < defbase_tot) {
+ groups[dw->def_nr] = true;
+ found = true;
+ }
+ }
+ return found;
+}
+static EnumPropertyItem *weight_paint_sample_enum_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ if (C) {
+ wmWindow *win = CTX_wm_window(C);
+ if (win && win->eventstate) {
+ ViewContext vc;
+ Mesh *me;
+
+ view3d_set_viewcontext(C, &vc);
+ me = BKE_mesh_from_object(vc.obact);
+
+ if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
+ const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups");
+ bool found = false;
+ uint index;
+
+ const int mval[2] = {
+ win->eventstate->x - vc.ar->winrct.xmin,
+ win->eventstate->y - vc.ar->winrct.ymin,
+ };
+
+ view3d_operator_needs_opengl(C);
+ ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
+
+ if (use_vert_sel) {
+ if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) {
+ MDeformVert *dvert = &me->dvert[index];
+ found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
+ }
+ }
+ else {
+ if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
+ const MPoly *mp = &me->mpoly[index];
+ uint fidx = mp->totloop - 1;
+
+ do {
+ MDeformVert *dvert = &me->dvert[me->mloop[mp->loopstart + fidx].v];
+ found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
+ } while (fidx--);
+ }
+ }
+
+ if (found == false) {
+ MEM_freeN(groups);
+ }
+ else {
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+ bDeformGroup *dg;
+ for (dg = vc.obact->defbase.first; dg && i < defbase_tot; i++, dg = dg->next) {
+ if (groups[i]) {
+ item_tmp.identifier = item_tmp.name = dg->name;
+ item_tmp.value = i;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ MEM_freeN(groups);
+ return item;
+ }
+ }
+ }
+ }
+
+ return DummyRNA_NULL_items;
+}
+
+static int weight_sample_group_exec(bContext *C, wmOperator *op)
+{
+ int type = RNA_enum_get(op->ptr, "group");
+ ViewContext vc;
+ view3d_set_viewcontext(C, &vc);
+
+ BLI_assert(type + 1 >= 0);
+ vc.obact->actdef = type + 1;
+
+ DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact);
+ return OPERATOR_FINISHED;
+}
+
+/* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather than its own operator */
+void PAINT_OT_weight_sample_group(wmOperatorType *ot)
+{
+ PropertyRNA *prop = NULL;
+
+ /* identifiers */
+ ot->name = "Weight Paint Sample Group";
+ ot->idname = "PAINT_OT_weight_sample_group";
+ ot->description = "Select one of the vertex groups available under current mouse position";
+
+ /* api callbacks */
+ ot->exec = weight_sample_group_exec;
+ ot->invoke = WM_menu_invoke;
+ ot->poll = weight_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* keyingset to use (dynamic enum) */
+ prop = RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
+ RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weight Set Operator
+ * \{ */
+
+/* fills in the selected faces with the current weight and vertex group */
+static bool weight_paint_set(Object *ob, float paintweight)
+{
+ Mesh *me = ob->data;
+ const MPoly *mp;
+ MDeformWeight *dw, *dw_prev;
+ int vgroup_active, vgroup_mirror = -1;
+ uint index;
+ const bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+
+ /* mutually exclusive, could be made into a */
+ const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(me);
+
+ if (me->totpoly == 0 || me->dvert == NULL || !me->mpoly) {
+ return false;
+ }
+
+ vgroup_active = ob->actdef - 1;
+
+ /* if mirror painting, find the other group */
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ vgroup_mirror = ED_wpaint_mirror_vgroup_ensure(ob, vgroup_active);
+ }
+
+ struct WPaintPrev wpp;
+ wpaint_prev_create(&wpp, me->dvert, me->totvert);
+
+ for (index = 0, mp = me->mpoly; index < me->totpoly; index++, mp++) {
+ uint fidx = mp->totloop - 1;
+
+ if ((paint_selmode == SCE_SELECT_FACE) && !(mp->flag & ME_FACE_SEL)) {
+ continue;
+ }
+
+ do {
+ uint vidx = me->mloop[mp->loopstart + fidx].v;
+
+ if (!me->dvert[vidx].flag) {
+ if ((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) {
+ continue;
+ }
+
+ dw = defvert_verify_index(&me->dvert[vidx], vgroup_active);
+ if (dw) {
+ dw_prev = defvert_verify_index(wpp.wpaint_prev + vidx, vgroup_active);
+ dw_prev->weight = dw->weight; /* set the undo weight */
+ dw->weight = paintweight;
+
+ if (me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
+ int j = mesh_get_x_mirror_vert(ob, NULL, vidx, topology);
+ if (j >= 0) {
+ /* copy, not paint again */
+ if (vgroup_mirror != -1) {
+ dw = defvert_verify_index(me->dvert + j, vgroup_mirror);
+ dw_prev = defvert_verify_index(wpp.wpaint_prev + j, vgroup_mirror);
+ }
+ else {
+ dw = defvert_verify_index(me->dvert + j, vgroup_active);
+ dw_prev = defvert_verify_index(wpp.wpaint_prev + j, vgroup_active);
+ }
+ dw_prev->weight = dw->weight; /* set the undo weight */
+ dw->weight = paintweight;
+ }
+ }
+ }
+ me->dvert[vidx].flag = 1;
+ }
+
+ } while (fidx--);
+ }
+
+ {
+ MDeformVert *dv = me->dvert;
+ for (index = me->totvert; index != 0; index--, dv++) {
+ dv->flag = 0;
+ }
+ }
+
+ wpaint_prev_destroy(&wpp);
+
+ DAG_id_tag_update(&me->id, 0);
+
+ return true;
+}
+
+
+static int weight_paint_set_exec(bContext *C, wmOperator *op)
+{
+ struct Scene *scene = CTX_data_scene(C);
+ Object *obact = CTX_data_active_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
+ float vgroup_weight = BKE_brush_weight_get(scene, brush);
+
+ if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, NULL) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (weight_paint_set(obact, vgroup_weight)) {
+ ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void PAINT_OT_weight_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Weight";
+ ot->idname = "PAINT_OT_weight_set";
+ ot->description = "Fill the active vertex group with the current paint weight";
+
+ /* api callbacks */
+ ot->exec = weight_paint_set_exec;
+ ot->poll = mask_paint_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Interactive Weight Gradient Operator
+ * \{ */
+
+/* *** VGroups Gradient *** */
+typedef struct DMGradient_vertStore {
+ float sco[2];
+ float weight_orig;
+ enum {
+ VGRAD_STORE_NOP = 0,
+ VGRAD_STORE_DW_EXIST = (1 << 0)
+ } flag;
+} DMGradient_vertStore;
+
+typedef struct DMGradient_vertStoreBase {
+ struct WPaintPrev wpp;
+ DMGradient_vertStore elem[0];
+} DMGradient_vertStoreBase;
+
+typedef struct DMGradient_userData {
+ struct ARegion *ar;
+ Scene *scene;
+ Mesh *me;
+ Brush *brush;
+ const float *sco_start; /* [2] */
+ const float *sco_end; /* [2] */
+ float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */
+ int def_nr;
+ bool is_init;
+ DMGradient_vertStoreBase *vert_cache;
+ /* only for init */
+ BLI_bitmap *vert_visit;
+
+ /* options */
+ short use_select;
+ short type;
+ float weightpaint;
+} DMGradient_userData;
+
+static void gradientVert_update(DMGradient_userData *grad_data, int index)
+{
+ Mesh *me = grad_data->me;
+ DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
+ float alpha;
+
+ if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
+ alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end);
+ }
+ else {
+ BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL);
+ alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
+ }
+ /* no need to clamp 'alpha' yet */
+
+ /* adjust weight */
+ alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f);
+
+ if (alpha != 0.0f) {
+ MDeformVert *dv = &me->dvert[index];
+ MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr);
+ // dw->weight = alpha; // testing
+ int tool = grad_data->brush->vertexpaint_tool;
+ float testw;
+
+ /* init if we just added */
+ testw = ED_wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha);
+ CLAMP(testw, 0.0f, 1.0f);
+ dw->weight = testw;
+ }
+ else {
+ MDeformVert *dv = &me->dvert[index];
+ if (vs->flag & VGRAD_STORE_DW_EXIST) {
+ /* normally we NULL check, but in this case we know it exists */
+ MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
+ dw->weight = vs->weight_orig;
+ }
+ else {
+ /* wasn't originally existing, remove */
+ MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
+ if (dw) {
+ defvert_remove_group(dv, dw);
+ }
+ }
+ }
+}
+
+static void gradientVertUpdate__mapFunc(
+ void *userData, int index, const float UNUSED(co[3]),
+ const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+ DMGradient_userData *grad_data = userData;
+ Mesh *me = grad_data->me;
+ if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) {
+ DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
+ if (vs->sco[0] != FLT_MAX) {
+ gradientVert_update(grad_data, index);
+ }
+ }
+}
+
+static void gradientVertInit__mapFunc(
+ void *userData, int index, const float co[3],
+ const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+ DMGradient_userData *grad_data = userData;
+ Mesh *me = grad_data->me;
+
+ if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) {
+ /* run first pass only,
+ * the screen coords of the verts need to be cached because
+ * updating the mesh may move them about (entering feedback loop) */
+
+ if (BLI_BITMAP_TEST(grad_data->vert_visit, index) == 0) {
+ DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
+ if (ED_view3d_project_float_object(grad_data->ar,
+ co, vs->sco,
+ V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ {
+ /* ok */
+ MDeformVert *dv = &me->dvert[index];
+ const MDeformWeight *dw;
+ dw = defvert_find_index(dv, grad_data->def_nr);
+ if (dw) {
+ vs->weight_orig = dw->weight;
+ vs->flag = VGRAD_STORE_DW_EXIST;
+ }
+ else {
+ vs->weight_orig = 0.0f;
+ vs->flag = VGRAD_STORE_NOP;
+ }
+
+ BLI_BITMAP_ENABLE(grad_data->vert_visit, index);
+
+ gradientVert_update(grad_data, index);
+ }
+ else {
+ /* no go */
+ copy_v2_fl(vs->sco, FLT_MAX);
+ }
+ }
+ }
+}
+
+static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ wmGesture *gesture = op->customdata;
+ DMGradient_vertStoreBase *vert_cache = gesture->userdata;
+ int ret = WM_gesture_straightline_modal(C, op, event);
+
+ if (ret & OPERATOR_RUNNING_MODAL) {
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */
+ /* generally crap! redo! */
+ WM_gesture_straightline_cancel(C, op);
+ ret &= ~OPERATOR_RUNNING_MODAL;
+ ret |= OPERATOR_FINISHED;
+ }
+ }
+
+ if (ret & OPERATOR_CANCELLED) {
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ if (vert_cache->wpp.wpaint_prev) {
+ BKE_defvert_array_free_elems(me->dvert, me->totvert);
+ BKE_defvert_array_copy(me->dvert, vert_cache->wpp.wpaint_prev, me->totvert);
+ wpaint_prev_destroy(&vert_cache->wpp);
+ }
+ MEM_freeN(vert_cache);
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ }
+ else if (ret & OPERATOR_FINISHED) {
+ wpaint_prev_destroy(&vert_cache->wpp);
+ MEM_freeN(vert_cache);
+ }
+
+ return ret;
+}
+
+static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
+{
+ wmGesture *gesture = op->customdata;
+ DMGradient_vertStoreBase *vert_cache;
+ struct ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ int x_start = RNA_int_get(op->ptr, "xstart");
+ int y_start = RNA_int_get(op->ptr, "ystart");
+ int x_end = RNA_int_get(op->ptr, "xend");
+ int y_end = RNA_int_get(op->ptr, "yend");
+ float sco_start[2] = {x_start, y_start};
+ float sco_end[2] = {x_end, y_end};
+ const bool is_interactive = (gesture != NULL);
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
+
+ DMGradient_userData data = {NULL};
+
+ if (is_interactive) {
+ if (gesture->userdata == NULL) {
+ gesture->userdata = MEM_mallocN(
+ sizeof(DMGradient_vertStoreBase) +
+ (sizeof(DMGradient_vertStore) * me->totvert),
+ __func__);
+ gesture->userdata_free = false;
+ data.is_init = true;
+
+ wpaint_prev_create(&((DMGradient_vertStoreBase *)gesture->userdata)->wpp, me->dvert, me->totvert);
+
+ /* on init only, convert face -> vert sel */
+ if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
+ BKE_mesh_flush_select_from_polys(me);
+ }
+ }
+
+ vert_cache = gesture->userdata;
+ }
+ else {
+ if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ data.is_init = true;
+ vert_cache = MEM_mallocN(
+ sizeof(DMGradient_vertStoreBase) +
+ (sizeof(DMGradient_vertStore) * me->totvert),
+ __func__);
+ }
+
+ data.ar = ar;
+ data.scene = scene;
+ data.me = ob->data;
+ data.sco_start = sco_start;
+ data.sco_end = sco_end;
+ data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
+ data.def_nr = ob->actdef - 1;
+ data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL));
+ data.vert_cache = vert_cache;
+ data.vert_visit = NULL;
+ data.type = RNA_enum_get(op->ptr, "type");
+
+ {
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ VPaint *wp = ts->wpaint;
+ struct Brush *brush = BKE_paint_brush(&wp->paint);
+
+ curvemapping_initialize(brush->curve);
+
+ data.brush = brush;
+ data.weightpaint = BKE_brush_weight_get(scene, brush);
+ }
+
+ ED_view3d_init_mats_rv3d(ob, ar->regiondata);
+
+ if (data.is_init) {
+ data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__);
+
+ dm->foreachMappedVert(dm, gradientVertInit__mapFunc, &data, DM_FOREACH_NOP);
+
+ MEM_freeN(data.vert_visit);
+ data.vert_visit = NULL;
+ }
+ else {
+ dm->foreachMappedVert(dm, gradientVertUpdate__mapFunc, &data, DM_FOREACH_NOP);
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ if (is_interactive == false) {
+ MEM_freeN(vert_cache);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int ret;
+
+ if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ret = WM_gesture_straightline_invoke(C, op, event);
+ if (ret & OPERATOR_RUNNING_MODAL) {
+ struct ARegion *ar = CTX_wm_region(C);
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ /* TODO, hardcoded, extend WM_gesture_straightline_ */
+ if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
+ wmGesture *gesture = op->customdata;
+ gesture->mode = 1;
+ }
+ }
+ }
+ return ret;
+}
+
+void PAINT_OT_weight_gradient(wmOperatorType *ot)
+{
+ /* defined in DNA_space_types.h */
+ static EnumPropertyItem gradient_types[] = {
+ {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""},
+ {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Weight Gradient";
+ ot->idname = "PAINT_OT_weight_gradient";
+ ot->description = "Draw a line to apply a weight gradient to selected vertices";
+
+ /* api callbacks */
+ ot->invoke = paint_weight_gradient_invoke;
+ ot->modal = paint_weight_gradient_modal;
+ ot->exec = paint_weight_gradient_exec;
+ ot->poll = weight_paint_poll;
+ ot->cancel = WM_gesture_straightline_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
new file mode 100644
index 00000000000..4d70d82d5c6
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.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/sculpt_paint/paint_vertex_weight_utils.c
+ * \ingroup edsculpt
+ *
+ * Intended for use by `paint_vertex.c` & `paint_vertex_weight_ops.c`.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string_utils.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_action.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object_deform.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "paint_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name Weight Paint Sanity Checks
+ * \{ */
+
+/* ensure we have data on wpaint start, add if needed */
+bool ED_wpaint_ensure_data(
+ bContext *C, struct ReportList *reports,
+ enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ if (vgroup_index) {
+ vgroup_index->active = -1;
+ vgroup_index->mirror = -1;
+ }
+
+ if (scene->obedit) {
+ return false;
+ }
+
+ if (me == NULL || me->totpoly == 0) {
+ return false;
+ }
+
+ /* if nothing was added yet, we make dverts and a vertex deform group */
+ if (!me->dvert) {
+ BKE_object_defgroup_data_create(&me->id);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ }
+
+ /* this happens on a Bone select, when no vgroup existed yet */
+ if (ob->actdef <= 0) {
+ Object *modob;
+ if ((modob = modifiers_isDeformedByArmature(ob))) {
+ Bone *actbone = ((bArmature *)modob->data)->act_bone;
+ if (actbone) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name);
+
+ if (pchan) {
+ bDeformGroup *dg = defgroup_find_name(ob, pchan->name);
+ if (dg == NULL) {
+ dg = BKE_object_defgroup_add_name(ob, pchan->name); /* sets actdef */
+ }
+ else {
+ int actdef = 1 + BLI_findindex(&ob->defbase, dg);
+ BLI_assert(actdef >= 0);
+ ob->actdef = actdef;
+ }
+ }
+ }
+ }
+ }
+ if (BLI_listbase_is_empty(&ob->defbase)) {
+ BKE_object_defgroup_add(ob);
+ }
+
+ /* ensure we don't try paint onto an invalid group */
+ if (ob->actdef <= 0) {
+ BKE_report(reports, RPT_WARNING, "No active vertex group for painting, aborting");
+ return false;
+ }
+
+ if (vgroup_index) {
+ vgroup_index->active = ob->actdef - 1;
+ }
+
+ if (flag & WPAINT_ENSURE_MIRROR) {
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ int mirror = ED_wpaint_mirror_vgroup_ensure(ob, ob->actdef - 1);
+ if (vgroup_index) {
+ vgroup_index->mirror = mirror;
+ }
+ }
+ }
+
+ return true;
+}
+/** \} */
+
+/* mirror_vgroup is set to -1 when invalid */
+int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
+{
+ bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active);
+
+ if (defgroup) {
+ int mirrdef;
+ char name_flip[MAXBONENAME];
+
+ BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
+ mirrdef = defgroup_name_index(ob, name_flip);
+ if (mirrdef == -1) {
+ if (BKE_defgroup_new(ob, name_flip)) {
+ mirrdef = BLI_listbase_count(&ob->defbase) - 1;
+ }
+ }
+
+ /* curdef should never be NULL unless this is
+ * a lamp and BKE_object_defgroup_add_name fails */
+ return mirrdef;
+ }
+
+ return -1;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Weight Blending Modes
+ * \{ */
+
+BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha)
+{
+ const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */
+ return (paintval * talpha) + (weight * (1.0f - talpha));
+}
+BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha)
+{
+ return weight + (paintval * alpha);
+}
+BLI_INLINE float wval_sub(const float weight, const float paintval, const float alpha)
+{
+ return weight - (paintval * alpha);
+}
+BLI_INLINE float wval_mul(const float weight, const float paintval, const float alpha)
+{ /* first mul, then blend the fac */
+ return ((1.0f - alpha) + (alpha * paintval)) * weight;
+}
+BLI_INLINE float wval_lighten(const float weight, const float paintval, const float alpha)
+{
+ return (weight < paintval) ? wval_blend(weight, paintval, alpha) : weight;
+}
+BLI_INLINE float wval_darken(const float weight, const float paintval, const float alpha)
+{
+ return (weight > paintval) ? wval_blend(weight, paintval, alpha) : weight;
+}
+
+/* mainly for color */
+BLI_INLINE float wval_colordodge(float weight, float paintval, float fac)
+{
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ temp = (paintval == 1.0f) ? 1.0f : min_ff((weight * (225.0f / 255.0f)) / (1.0f - paintval), 1.0f);
+ return mfac * weight + temp * fac;
+}
+BLI_INLINE float wval_difference(float weight, float paintval, float fac)
+{
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ temp = fabsf(weight - paintval);
+ return mfac * weight + temp * fac;
+}
+BLI_INLINE float wval_screen(float weight, float paintval, float fac)
+{
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ temp = max_ff(1.0f - (((1.0f - weight) * (1.0f - paintval))), 0);
+ return mfac * weight + temp * fac;
+}
+BLI_INLINE float wval_hardlight(float weight, float paintval, float fac)
+{
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ if (paintval > 0.5f) {
+ temp = 1.0f - ((1.0f - 2.0f * (paintval - 0.5f)) * (1.0f - weight));
+ }
+ else {
+ temp = (2.0f * paintval * weight);
+ }
+ return mfac * weight + temp * fac;
+}
+BLI_INLINE float wval_overlay(float weight, float paintval, float fac)
+{
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ if (weight > 0.5f) {
+ temp = 1.0f - ((1.0f - 2.0f * (weight - 0.5f)) * (1.0f - paintval));
+ }
+ else {
+ temp = (2.0f * paintval * weight);
+ }
+ return mfac * weight + temp * fac;
+}
+BLI_INLINE float wval_softlight(float weight, float paintval, float fac)
+{
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ if (weight < 0.5f) {
+ temp = ((2.0f * ((paintval / 2.0f) + 0.25f)) * weight);
+ }
+ else {
+ temp = 1.0f - (2.0f * (1.0f - ((paintval / 2.0f) + 0.25f)) * (1.0f - weight));
+ }
+ return temp * fac + weight * mfac;
+}
+BLI_INLINE float wval_exclusion(float weight, float paintval, float fac)
+{
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ temp = 0.5f - ((2.0f * (weight - 0.5f) * (paintval - 0.5f)));
+ return temp * fac + weight * mfac;
+}
+
+/* vpaint has 'vpaint_blend_tool' */
+/* result is not clamped from [0-1] */
+float ED_wpaint_blend_tool(
+ const int tool,
+ /* dw->weight */
+ const float weight,
+ const float paintval, const float alpha)
+{
+ switch (tool) {
+ case PAINT_BLEND_MIX:
+ case PAINT_BLEND_AVERAGE:
+ case PAINT_BLEND_SMEAR:
+ case PAINT_BLEND_BLUR: return wval_blend(weight, paintval, alpha);
+ case PAINT_BLEND_ADD: return wval_add(weight, paintval, alpha);
+ case PAINT_BLEND_SUB: return wval_sub(weight, paintval, alpha);
+ case PAINT_BLEND_MUL: return wval_mul(weight, paintval, alpha);
+ case PAINT_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha);
+ case PAINT_BLEND_DARKEN: return wval_darken(weight, paintval, alpha);
+ /* Mostly make sense for color: support anyway. */
+ case PAINT_BLEND_COLORDODGE: return wval_colordodge(weight, paintval, alpha);
+ case PAINT_BLEND_DIFFERENCE: return wval_difference(weight, paintval, alpha);
+ case PAINT_BLEND_SCREEN: return wval_screen(weight, paintval, alpha);
+ case PAINT_BLEND_HARDLIGHT: return wval_hardlight(weight, paintval, alpha);
+ case PAINT_BLEND_OVERLAY: return wval_overlay(weight, paintval, alpha);
+ case PAINT_BLEND_SOFTLIGHT: return wval_softlight(weight, paintval, alpha);
+ case PAINT_BLEND_EXCLUSION: return wval_exclusion(weight, paintval, alpha);
+ /* Only for color: just use blend. */
+ case PAINT_BLEND_LUMINOCITY:
+ case PAINT_BLEND_SATURATION:
+ case PAINT_BLEND_HUE:
+ case PAINT_BLEND_ALPHA_SUB:
+ case PAINT_BLEND_ALPHA_ADD:
+ default: return wval_blend(weight, paintval, alpha);
+ }
+}
+
+/** \} */ \ No newline at end of file
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 53434b18d06..1f0d8e5d29b 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -39,7 +39,6 @@
#include "BLI_blenlib.h"
#include "BLI_dial.h"
#include "BLI_task.h"
-#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -165,111 +164,12 @@ static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f);
}
-/* Factor of brush to have rake point following behind
- * (could be configurable but this is reasonable default). */
-#define SCULPT_RAKE_BRUSH_FACTOR 0.25f
-
-struct SculptRakeData {
- float follow_dist;
- float follow_co[3];
-};
-
typedef enum StrokeFlags {
CLIP_X = 1,
CLIP_Y = 2,
CLIP_Z = 4
} StrokeFlags;
-/* Cache stroke properties. Used because
- * RNA property lookup isn't particularly fast.
- *
- * For descriptions of these settings, check the operator properties.
- */
-typedef struct StrokeCache {
- /* Invariants */
- float initial_radius;
- float scale[3];
- int flag;
- float clip_tolerance[3];
- float initial_mouse[2];
-
- /* Variants */
- float radius;
- float radius_squared;
- float true_location[3];
- float location[3];
-
- bool pen_flip;
- bool invert;
- float pressure;
- float mouse[2];
- float bstrength;
- float normal_weight; /* from brush (with optional override) */
-
- /* The rest is temporary storage that isn't saved as a property */
-
- bool first_time; /* Beginning of stroke may do some things special */
-
- /* from ED_view3d_ob_project_mat_get() */
- float projection_mat[4][4];
-
- /* Clean this up! */
- ViewContext *vc;
- Brush *brush;
-
- float special_rotation;
- float grab_delta[3], grab_delta_symmetry[3];
- float old_grab_location[3], orig_grab_location[3];
-
- /* screen-space rotation defined by mouse motion */
- float rake_rotation[4], rake_rotation_symmetry[4];
- bool is_rake_rotation_valid;
- struct SculptRakeData rake_data;
-
- int symmetry; /* Symmetry index between 0 and 7 bit combo 0 is Brush only;
- * 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
- int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
- float true_view_normal[3];
- float view_normal[3];
-
- /* sculpt_normal gets calculated by calc_sculpt_normal(), then the
- * sculpt_normal_symm gets updated quickly with the usual symmetry
- * transforms */
- float sculpt_normal[3];
- float sculpt_normal_symm[3];
-
- /* Used for area texture mode, local_mat gets calculated by
- * calc_brush_local_mat() and used in tex_strength(). */
- float brush_local_mat[4][4];
-
- float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */
- int tile_pass;
-
- float last_center[3];
- int radial_symmetry_pass;
- float symm_rot_mat[4][4];
- float symm_rot_mat_inv[4][4];
- bool original;
- float anchored_location[3];
-
- float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
- Dial *dial;
-
- char saved_active_brush_name[MAX_ID_NAME];
- char saved_mask_brush_tool;
- int saved_smooth_size; /* smooth tool copies the size of the current tool */
- bool alt_smooth;
-
- float plane_trim_squared;
-
- bool supports_gravity;
- float true_gravity_direction[3];
- float gravity_direction[3];
-
- rcti previous_r; /* previous redraw rectangle */
- rcti current_r; /* current redraw rectangle */
-} StrokeCache;
-
/************** Access to original unmodified vertex data *************/
typedef struct {
@@ -476,41 +376,6 @@ static bool sculpt_stroke_is_dynamic_topology(
/*** paint mesh ***/
-/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */
-typedef struct SculptThreadedTaskData {
- Sculpt *sd;
- Object *ob;
- Brush *brush;
- PBVHNode **nodes;
- int totnode;
-
- /* Data specific to some callbacks. */
- /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out
- * what it is, and memory overhead is ridiculous anyway... */
- float flippedbstrength;
- float angle;
- float strength;
- bool smooth_mask;
- bool has_bm_orco;
-
- SculptProjectVector *spvc;
- float *offset;
- float *grab_delta;
- float *cono;
- float *area_no;
- float *area_no_sp;
- float *area_co;
- float (*mat)[4];
- float (*vertCos)[3];
-
- /* 0=towards view, 1=flipped */
- float (*area_cos)[3];
- float (*area_nos)[3];
- int *count;
-
- ThreadMutex mutex;
-} SculptThreadedTaskData;
-
static void paint_mesh_restore_co_task_cb(void *userdata, const int n)
{
SculptThreadedTaskData *data = userdata;
@@ -600,7 +465,7 @@ static void sculpt_extend_redraw_rect_previous(Object *ob, rcti *rect)
}
/* Get a screen-space rectangle of the modified area */
-static bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
+bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
Object *ob, rcti *rect)
{
PBVH *pbvh = ob->sculpt->pbvh;
@@ -650,17 +515,7 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar,
/************************ Brush Testing *******************/
-typedef struct SculptBrushTest {
- float radius_squared;
- float location[3];
- float dist;
- int mirror_symmetry_pass;
-
- /* View3d clipping - only set rv3d for clipping */
- RegionView3D *clip_rv3d;
-} SculptBrushTest;
-
-static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
+void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
{
RegionView3D *rv3d = ss->cache->vc->rv3d;
@@ -668,6 +523,10 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
copy_v3_v3(test->location, ss->cache->location);
test->dist = 0.0f; /* just for initialize */
+ /* Only for 2D projection. */
+ zero_v4(test->plane_view);
+ zero_v4(test->plane_tool);
+
test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass;
if (rv3d->rflag & RV3D_CLIPPING) {
@@ -689,7 +548,7 @@ BLI_INLINE bool sculpt_brush_test_clipping(const SculptBrushTest *test, const fl
return ED_view3d_clipping_test(rv3d, symm_co, true);
}
-static bool sculpt_brush_test(SculptBrushTest *test, const float co[3])
+bool sculpt_brush_test_sphere(SculptBrushTest *test, const float co[3])
{
float distsq = len_squared_v3v3(co, test->location);
@@ -705,7 +564,7 @@ static bool sculpt_brush_test(SculptBrushTest *test, const float co[3])
}
}
-static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
+bool sculpt_brush_test_sphere_sq(SculptBrushTest *test, const float co[3])
{
float distsq = len_squared_v3v3(co, test->location);
@@ -721,7 +580,7 @@ static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
}
}
-static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3])
+bool sculpt_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3])
{
if (sculpt_brush_test_clipping(test, co)) {
return 0;
@@ -729,7 +588,25 @@ static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3
return len_squared_v3v3(co, test->location) <= test->radius_squared;
}
-static bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4])
+bool sculpt_brush_test_circle_sq(SculptBrushTest *test, const float co[3])
+{
+ float co_proj[3];
+ closest_to_plane_normalized_v3(co_proj, test->plane_view, co);
+ float distsq = len_squared_v3v3(co_proj, test->location);
+
+ if (distsq <= test->radius_squared) {
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
+ test->dist = distsq;
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4])
{
float side = M_SQRT1_2;
float local_co[3];
@@ -758,7 +635,36 @@ static bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], flo
}
}
-static float frontface(Brush *br, const float sculpt_normal[3],
+SculptBrushTestFn sculpt_brush_test_init_with_falloff_shape(
+ SculptSession *ss, SculptBrushTest *test, char falloff_shape)
+{
+ sculpt_brush_test_init(ss, test);
+ SculptBrushTestFn sculpt_brush_test_sq_fn;
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ sculpt_brush_test_sq_fn = sculpt_brush_test_sphere_sq;
+ }
+ else {
+ /* PAINT_FALLOFF_SHAPE_TUBE */
+ plane_from_point_normal_v3(test->plane_view, test->location, ss->cache->view_normal);
+ sculpt_brush_test_sq_fn = sculpt_brush_test_circle_sq;
+ }
+ return sculpt_brush_test_sq_fn;
+}
+
+const float *sculpt_brush_frontface_normal_from_falloff_shape(
+ SculptSession *ss, char falloff_shape)
+{
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ return ss->cache->sculpt_normal_symm;
+ }
+ else {
+ /* PAINT_FALLOFF_SHAPE_TUBE */
+ return ss->cache->view_normal;
+ }
+}
+
+
+static float frontface(const Brush *br, const float sculpt_normal[3],
const short no[3], const float fno[3])
{
if (br->flag & BRUSH_FRONTFACE) {
@@ -784,7 +690,7 @@ static float frontface(Brush *br, const float sculpt_normal[3],
static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], const float area_no[3])
{
- if (sculpt_brush_test_fast(test, co)) {
+ if (sculpt_brush_test_sphere_fast(test, co)) {
float t1[3], t2[3], t3[3], dist;
sub_v3_v3v3(t1, location, co);
@@ -821,10 +727,9 @@ static float calc_overlap(StrokeCache *cache, const char symm, const char axis,
flip_v3_v3(mirror, cache->true_location, symm);
if (axis != 0) {
- float mat[4][4];
- unit_m4(mat);
- rotate_m4(mat, axis, angle);
- mul_m4_v3(mat, mirror);
+ float mat[3][3];
+ axis_angle_to_mat3_single(mat, axis, angle);
+ mul_m3_v3(mat, mirror);
}
/* distsq = len_squared_v3v3(mirror, cache->traced_location); */
@@ -897,18 +802,22 @@ static void calc_area_normal_and_center_task_cb(void *userdata, const int n)
float (*area_cos)[3] = data->area_cos;
PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
+ SculptUndoNode *unode = NULL;
float private_co[2][3] = {{0.0f}};
float private_no[2][3] = {{0.0f}};
int private_count[2] = {0};
- bool use_original;
+ bool use_original = false;
- unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
+ if (ss->cache->original) {
+ unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ use_original = (unode->co || unode->bm_entry);
+ }
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
- use_original = (ss->cache->original && (unode->co || unode->bm_entry));
/* when the mesh is edited we can't rely on original coords
* (original mesh may not even have verts in brush radius) */
@@ -930,7 +839,7 @@ static void calc_area_normal_and_center_task_cb(void *userdata, const int n)
closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
- if (sculpt_brush_test_fast(&test, co)) {
+ if (sculpt_brush_test_sq_fn(&test, co)) {
float no[3];
int flip_index;
@@ -964,7 +873,7 @@ static void calc_area_normal_and_center_task_cb(void *userdata, const int n)
co = vd.co;
}
- if (sculpt_brush_test_fast(&test, co)) {
+ if (sculpt_brush_test_sq_fn(&test, co)) {
float no_buf[3];
const float *no;
int flip_index;
@@ -1030,8 +939,9 @@ static void calc_area_center(
int count[2] = {0};
+ /* Intentionally set 'sd' to NULL since we share logic with vertex paint. */
SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode,
+ .sd = NULL, .ob = ob, .brush = brush, .nodes = nodes, .totnode = totnode,
.has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = NULL, .count = count,
};
BLI_mutex_init(&data.mutex);
@@ -1054,42 +964,53 @@ static void calc_area_center(
}
}
-
static void calc_area_normal(
Sculpt *sd, Object *ob,
PBVHNode **nodes, int totnode,
float r_area_no[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
+ bool use_threading = (sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT;
+ sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, use_threading, r_area_no);
+}
+
+/* expose 'calc_area_normal' externally. */
+void sculpt_pbvh_calc_area_normal(
+ const Brush *brush, Object *ob,
+ PBVHNode **nodes, int totnode,
+ bool use_threading,
+ float r_area_no[3])
+{
SculptSession *ss = ob->sculpt;
const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
- int n;
/* 0=towards view, 1=flipped */
float area_nos[2][3] = {{0.0f}};
int count[2] = {0};
+ /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode,
+ .sd = NULL, .ob = ob, .brush = brush, .nodes = nodes, .totnode = totnode,
.has_bm_orco = has_bm_orco, .area_cos = NULL, .area_nos = area_nos, .count = count,
};
BLI_mutex_init(&data.mutex);
BLI_task_parallel_range(
0, totnode, &data, calc_area_normal_and_center_task_cb,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
+ use_threading);
BLI_mutex_end(&data.mutex);
/* for area normal */
- for (n = 0; n < ARRAY_SIZE(area_nos); n++) {
- if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) {
+ for (int i = 0; i < ARRAY_SIZE(area_nos); i++) {
+ if (normalize_v3_v3(r_area_no, area_nos[i]) != 0.0f) {
break;
}
}
}
+
/* this calculates flatten center and area normal together,
* amortizing the memory bandwidth and loop overhead to calculate both at the same time */
static void calc_area_normal_and_center(
@@ -1108,8 +1029,9 @@ static void calc_area_normal_and_center(
int count[2] = {0};
+ /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode,
+ .sd = NULL, .ob = ob, .brush = brush, .nodes = nodes, .totnode = totnode,
.has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = area_nos, .count = count,
};
BLI_mutex_init(&data.mutex);
@@ -1238,17 +1160,17 @@ static float brush_strength(
}
/* Return a multiplier for brush strength on a particular vertex. */
-static float tex_strength(SculptSession *ss, Brush *br,
- const float brush_point[3],
- const float len,
- const short vno[3],
- const float fno[3],
- const float mask,
- const int thread_id)
+float tex_strength(SculptSession *ss, const Brush *br,
+ const float brush_point[3],
+ const float len,
+ const short vno[3],
+ const float fno[3],
+ const float mask,
+ const int thread_id)
{
StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene;
- MTex *mtex = &br->mtex;
+ const MTex *mtex = &br->mtex;
float avg = 1;
float rgba[4];
float point[3];
@@ -1317,15 +1239,8 @@ static float tex_strength(SculptSession *ss, Brush *br,
return avg;
}
-typedef struct {
- Sculpt *sd;
- SculptSession *ss;
- float radius_squared;
- bool original;
-} SculptSearchSphereData;
-
/* Test AABB against sphere */
-static bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
+bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
{
SculptSearchSphereData *data = data_v;
float *center = data->ss->cache->location, nearest[3];
@@ -1351,6 +1266,24 @@ static bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
return len_squared_v3(t) < data->radius_squared;
}
+/* 2D projection (distance to line). */
+bool sculpt_search_circle_cb(PBVHNode *node, void *data_v)
+{
+ SculptSearchCircleData *data = data_v;
+ float bb_min[3], bb_max[3];
+
+ if (data->original)
+ BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
+ else
+ BKE_pbvh_node_get_BB(node, bb_min, bb_min);
+
+ float dummy_co[3], dummy_depth;
+ const float dist_sq = dist_squared_ray_to_aabb_v3(
+ data->dist_ray_to_aabb_precalc, bb_min, bb_max, dummy_co, &dummy_depth);
+
+ return dist_sq < data->radius_squared || 1;
+}
+
/* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */
static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
{
@@ -1367,6 +1300,37 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float
}
}
+static PBVHNode **sculpt_pbvh_gather_generic(
+ Object *ob, Sculpt *sd, const Brush *brush, bool use_original, float radius_scale, int *r_totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes = NULL;
+
+ /* Build a list of all nodes that are potentially within the brush's area of influence */
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = SQUARE(ss->cache->radius * radius_scale),
+ .original = use_original,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
+ }
+ else {
+ struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
+ dist_squared_ray_to_aabb_v3_precalc(&dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal);
+ SculptSearchCircleData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = SQUARE(ss->cache->radius * radius_scale),
+ .original = use_original,
+ .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode);
+ }
+ return nodes;
+}
+
/* Calculate primary direction of movement for many brushes */
static void calc_sculpt_normal(
Sculpt *sd, Object *ob,
@@ -1413,6 +1377,10 @@ static void update_sculpt_normal(Sculpt *sd, Object *ob,
(cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
{
calc_sculpt_normal(sd, ob, nodes, totnode, cache->sculpt_normal);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(cache->sculpt_normal, cache->sculpt_normal, cache->view_normal);
+ normalize_v3(cache->sculpt_normal);
+ }
copy_v3_v3(cache->sculpt_normal_symm, cache->sculpt_normal);
}
else {
@@ -1633,30 +1601,54 @@ typedef struct SculptDoBrushSmoothGridDataChunk {
size_t tmpgrid_size;
} SculptDoBrushSmoothGridDataChunk;
+typedef struct {
+ SculptSession *ss;
+ const float *ray_start, *ray_normal;
+ bool hit;
+ float depth;
+ bool original;
+} SculptRaycastData;
+
+typedef struct {
+ const float *ray_start, *ray_normal;
+ bool hit;
+ float depth;
+ float detail;
+} SculptDetailRaycastData;
+
+typedef struct {
+ SculptSession *ss;
+ const float *ray_start, *ray_normal;
+ bool hit;
+ float depth;
+ float dist_sq_to_ray;
+ bool original;
+} SculptFindNearestToRayData;
+
static void do_smooth_brush_mesh_task_cb_ex(
void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const bool smooth_mask = data->smooth_mask;
float bstrength = data->strength;
PBVHVertexIter vd;
- SculptBrushTest test;
CLAMP(bstrength, 0.0f, 1.0f);
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, vd.co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, test.dist, vd.no, vd.fno,
- smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
- thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), thread_id);
if (smooth_mask) {
float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask;
val *= fade * bstrength;
@@ -1687,23 +1679,24 @@ static void do_smooth_brush_bmesh_task_cb_ex(
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const bool smooth_mask = data->smooth_mask;
float bstrength = data->strength;
PBVHVertexIter vd;
- SculptBrushTest test;
CLAMP(bstrength, 0.0f, 1.0f);
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, vd.co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, test.dist, vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask,
- thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask, thread_id);
if (smooth_mask) {
float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
val *= fade * bstrength;
@@ -1735,11 +1728,10 @@ static void do_smooth_brush_multires_task_cb_ex(
SculptDoBrushSmoothGridDataChunk *data_chunk = userdata_chunk;
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const bool smooth_mask = data->smooth_mask;
float bstrength = data->strength;
- SculptBrushTest test;
CCGElem **griddata, *gddata;
CCGKey key;
@@ -1752,7 +1744,9 @@ static void do_smooth_brush_multires_task_cb_ex(
int *grid_indices, totgrid, gridsize;
int i, x, y;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
CLAMP(bstrength, 0.0f, 1.0f);
@@ -1839,10 +1833,11 @@ static void do_smooth_brush_multires_task_cb_ex(
fno = CCG_elem_offset_no(&key, gddata, index);
mask = CCG_elem_offset_mask(&key, gddata, index);
- if (sculpt_brush_test(&test, co)) {
+ if (sculpt_brush_test_sq_fn(&test, co)) {
const float strength_mask = (smooth_mask ? 0.0f : *mask);
const float fade = bstrength * tex_strength(
- ss, brush, co, test.dist, NULL, fno, strength_mask, thread_id);
+ ss, brush, co, sqrtf(test.dist),
+ NULL, fno, strength_mask, thread_id);
float f = 1.0f / 16.0f;
if (x == 0 || x == gridsize - 1)
@@ -1949,18 +1944,21 @@ static void do_mask_brush_draw_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const float bstrength = ss->cache->bstrength;
PBVHVertexIter vd;
- SculptBrushTest test;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, vd.co)) {
- const float fade = tex_strength(ss, brush, vd.co, test.dist, vd.no, vd.fno, 0.0f, thread_id);
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, 0.0f, thread_id);
(*vd.mask) += fade * bstrength;
CLAMP(*vd.mask, 0, 1);
@@ -2006,23 +2004,25 @@ static void do_draw_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const float *offset = data->offset;
PBVHVertexIter vd;
- SculptBrushTest test;
float (*proxy)[3];
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, vd.co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* offset vertex */
const float fade = tex_strength(
- ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -2056,35 +2056,44 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
}
+/**
+ * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
+ */
static void do_crease_brush_task_cb_ex(
void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
SculptProjectVector *spvc = data->spvc;
const float flippedbstrength = data->flippedbstrength;
const float *offset = data->offset;
PBVHVertexIter vd;
- SculptBrushTest test;
float (*proxy)[3];
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, vd.co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* offset vertex */
const float fade = tex_strength(
- ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
float val1[3];
float val2[3];
/* first we pinch */
sub_v3_v3v3(val1, test.location, vd.co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(val1, val1, ss->cache->view_normal);
+ }
+
mul_v3_fl(val1, fade * flippedbstrength);
sculpt_project_v3(spvc, val1, val1);
@@ -2149,25 +2158,30 @@ static void do_pinch_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
PBVHVertexIter vd;
- SculptBrushTest test;
float (*proxy)[3];
const float bstrength = ss->cache->bstrength;
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, vd.co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
float val[3];
sub_v3_v3v3(val, test.location, vd.co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(val, val, ss->cache->view_normal);
+ }
mul_v3_v3fl(proxy[vd.i], val, fade);
if (vd.mvert)
@@ -2195,11 +2209,10 @@ static void do_grab_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const float *grab_delta = data->grab_delta;
PBVHVertexIter vd;
- SculptBrushTest test;
SculptOrigVertData orig_data;
float (*proxy)[3];
const float bstrength = ss->cache->bstrength;
@@ -2208,16 +2221,18 @@ static void do_grab_brush_task_cb_ex(
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
sculpt_orig_vert_data_update(&orig_data, &vd);
- if (sculpt_brush_test(&test, orig_data.co)) {
+ if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
const float fade = bstrength * tex_strength(
- ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f,
- thread_id);
+ ss, brush, orig_data.co, sqrtf(test.dist),
+ orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -2255,23 +2270,25 @@ static void do_nudge_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const float *cono = data->cono;
PBVHVertexIter vd;
- SculptBrushTest test;
float (*proxy)[3];
const float bstrength = ss->cache->bstrength;
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, vd.co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -2309,12 +2326,11 @@ static void do_snake_hook_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
SculptProjectVector *spvc = data->spvc;
const float *grab_delta = data->grab_delta;
PBVHVertexIter vd;
- SculptBrushTest test;
float (*proxy)[3];
const float bstrength = ss->cache->bstrength;
const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
@@ -2324,13 +2340,16 @@ static void do_snake_hook_brush_task_cb_ex(
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, vd.co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -2339,6 +2358,9 @@ static void do_snake_hook_brush_task_cb_ex(
float delta_pinch_init[3], delta_pinch[3];
sub_v3_v3v3(delta_pinch, vd.co, test.location);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal);
+ }
/* important to calculate based on the grabbed location (intentionally ignore fade here). */
add_v3_v3(delta_pinch, grab_delta);
@@ -2410,11 +2432,10 @@ static void do_thumb_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const float *cono = data->cono;
PBVHVertexIter vd;
- SculptBrushTest test;
SculptOrigVertData orig_data;
float (*proxy)[3];
const float bstrength = ss->cache->bstrength;
@@ -2423,16 +2444,18 @@ static void do_thumb_brush_task_cb_ex(
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
sculpt_orig_vert_data_update(&orig_data, &vd);
- if (sculpt_brush_test(&test, orig_data.co)) {
+ if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
const float fade = bstrength * tex_strength(
- ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f,
- thread_id);
+ ss, brush, orig_data.co, sqrtf(test.dist),
+ orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -2470,11 +2493,10 @@ static void do_rotate_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const float angle = data->angle;
PBVHVertexIter vd;
- SculptBrushTest test;
SculptOrigVertData orig_data;
float (*proxy)[3];
const float bstrength = ss->cache->bstrength;
@@ -2483,17 +2505,19 @@ static void do_rotate_brush_task_cb_ex(
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
sculpt_orig_vert_data_update(&orig_data, &vd);
- if (sculpt_brush_test(&test, orig_data.co)) {
+ if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
float vec[3], rot[3][3];
const float fade = bstrength * tex_strength(
- ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f,
- thread_id);
+ ss, brush, orig_data.co, sqrtf(test.dist),
+ orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id);
sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
@@ -2532,11 +2556,10 @@ static void do_layer_brush_task_cb_ex(
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const float *offset = data->offset;
PBVHVertexIter vd;
- SculptBrushTest test;
SculptOrigVertData orig_data;
float *layer_disp;
const float bstrength = ss->cache->bstrength;
@@ -2551,15 +2574,18 @@ static void do_layer_brush_task_cb_ex(
layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, data->nodes[n]);
BLI_mutex_unlock(&data->mutex);
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
sculpt_orig_vert_data_update(&orig_data, &vd);
- if (sculpt_brush_test(&test, orig_data.co)) {
+ if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
float *disp = &layer_disp[vd.i];
float val[3];
@@ -2616,22 +2642,24 @@ static void do_inflate_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
PBVHVertexIter vd;
- SculptBrushTest test;
float (*proxy)[3];
const float bstrength = ss->cache->bstrength;
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, vd.co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
float val[3];
if (vd.fno)
@@ -2694,6 +2722,10 @@ static void calc_sculpt_plane(
case SCULPT_DISP_DIR_AREA:
calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
+ normalize_v3(r_area_no);
+ }
break;
default:
@@ -2735,16 +2767,6 @@ static void calc_sculpt_plane(
}
}
-/* Projects a point onto a plane along the plane's normal */
-static void point_plane_project(
- float intr[3],
- const float co[3], const float plane_normal[3], const float plane_center[3])
-{
- sub_v3_v3v3(intr, co, plane_center);
- mul_v3_v3fl(intr, plane_normal, dot_v3v3(plane_normal, intr));
- sub_v3_v3v3(intr, co, intr);
-}
-
static int plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
{
return (!(brush->flag & BRUSH_PLANE_TRIM) ||
@@ -2752,26 +2774,18 @@ static int plane_trim(const StrokeCache *cache, const Brush *brush, const float
}
static bool plane_point_side_flip(
- const float co[3], const float plane_normal[3], const float plane_center[3],
+ const float co[3], const float plane[4],
const bool flip)
{
- float delta[3];
- float d;
-
- sub_v3_v3v3(delta, co, plane_center);
- d = dot_v3v3(plane_normal, delta);
-
+ float d = plane_point_side_v3(plane, co);
if (flip) d = -d;
-
return d <= 0.0f;
}
-static int plane_point_side(const float co[3], const float plane_normal[3], const float plane_center[3])
+static int plane_point_side(const float co[3], const float plane[4])
{
- float delta[3];
-
- sub_v3_v3v3(delta, co, plane_center);
- return dot_v3v3(plane_normal, delta) <= 0.0f;
+ float d = plane_point_side_v3(plane, co);
+ return d <= 0.0f;
}
static float get_offset(Sculpt *sd, SculptSession *ss)
@@ -2792,33 +2806,36 @@ static void do_flatten_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const float *area_no = data->area_no;
const float *area_co = data->area_co;
PBVHVertexIter vd;
- SculptBrushTest test;
float (*proxy)[3];
const float bstrength = ss->cache->bstrength;
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test_sq(&test, vd.co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, area_no, area_co);
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
- thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2867,28 +2884,31 @@ static void do_clay_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const float *area_no = data->area_no;
const float *area_co = data->area_co;
PBVHVertexIter vd;
- SculptBrushTest test;
float (*proxy)[3];
const bool flip = (ss->cache->bstrength < 0);
const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side_flip(vd.co, area_no, area_co, flip)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ if (plane_point_side_flip(vd.co, test.plane_tool, flip)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, area_no, area_co);
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2896,8 +2916,8 @@ static void do_clay_brush_task_cb_ex(
/* note, the normal from the vertices is ignored,
* causes glitch with planes, see: T44390 */
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
- thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2950,7 +2970,7 @@ static void do_clay_strips_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
float (*mat)[4] = data->mat;
const float *area_no_sp = data->area_no_sp;
const float *area_co = data->area_co;
@@ -2964,15 +2984,16 @@ static void do_clay_strips_brush_task_cb_ex(
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
sculpt_brush_test_init(ss, &test);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_cube(&test, vd.co, mat)) {
- if (plane_point_side_flip(vd.co, area_no_sp, area_co, flip)) {
+ if (plane_point_side_flip(vd.co, test.plane_tool, flip)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, area_no_sp, area_co);
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2980,8 +3001,8 @@ static void do_clay_strips_brush_task_cb_ex(
/* note, the normal from the vertices is ignored,
* causes glitch with planes, see: T44390 */
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, ss->cache->radius * test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ ss, brush, vd.co, ss->cache->radius * test.dist,
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3059,34 +3080,37 @@ static void do_fill_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const float *area_no = data->area_no;
const float *area_co = data->area_co;
PBVHVertexIter vd;
- SculptBrushTest test;
float (*proxy)[3];
const float bstrength = ss->cache->bstrength;
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side(vd.co, area_no, area_co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ if (plane_point_side(vd.co, test.plane_tool)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, area_no, area_co);
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3137,34 +3161,36 @@ static void do_scrape_brush_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
const float *area_no = data->area_no;
const float *area_co = data->area_co;
PBVHVertexIter vd;
- SculptBrushTest test;
float (*proxy)[3];
const float bstrength = ss->cache->bstrength;
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test_sq(&test, vd.co)) {
- if (!plane_point_side(vd.co, area_no, area_co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ if (!plane_point_side(vd.co, test.plane_tool)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, area_no, area_co);
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
- thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3215,22 +3241,23 @@ static void do_gravity_task_cb_ex(
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- Brush *brush = data->brush;
+ const Brush *brush = data->brush;
float *offset = data->offset;
PBVHVertexIter vd;
- SculptBrushTest test;
float (*proxy)[3];
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn =
+ sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (sculpt_brush_test_sq(&test, vd.co)) {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = tex_strength(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
- thread_id);
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3314,22 +3341,12 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *UNUSED(ups))
{
SculptSession *ss = ob->sculpt;
- SculptSearchSphereData data;
- PBVHNode **nodes = NULL;
- float radius;
- int n, totnode;
-
- /* Build a list of all nodes that are potentially within the
- * brush's area of influence */
- data.ss = ss;
- data.sd = sd;
-
- radius = ss->cache->radius * 1.25f;
-
- data.radius_squared = radius * radius;
- data.original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
- BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+ int n, totnode;
+ /* Build a list of all nodes that are potentially within the brush's area of influence */
+ const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
+ const float radius_scale = 1.25f;
+ PBVHNode **nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
/* Only act if some verts are inside the brush area */
if (totnode) {
@@ -3361,8 +3378,10 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified
BKE_pbvh_bmesh_update_topology(
ss->pbvh, mode,
ss->cache->location,
- (brush->flag & BRUSH_FRONTFACE) ? ss->cache->view_normal : NULL,
- ss->cache->radius);
+ ss->cache->view_normal,
+ ss->cache->radius,
+ (brush->flag & BRUSH_FRONTFACE) != 0,
+ (brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE));
}
MEM_freeN(nodes);
@@ -3385,16 +3404,12 @@ static void do_brush_action_task_cb(void *userdata, const int n)
static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups)
{
SculptSession *ss = ob->sculpt;
- SculptSearchSphereData data;
- PBVHNode **nodes = NULL;
int totnode;
/* Build a list of all nodes that are potentially within the brush's area of influence */
- data.ss = ss;
- data.sd = sd;
- data.radius_squared = ss->cache->radius_squared;
- data.original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
- BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+ const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
+ const float radius_scale = 1.0f;
+ PBVHNode **nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
/* Only act if some verts are inside the brush area */
if (totnode) {
@@ -3689,13 +3704,12 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
/* Flip all the editdata across the axis/axes specified by symm. Used to
* calculate multiple modifications to the mesh when symmetry is enabled. */
-static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
- const char axis, const float angle,
- const float UNUSED(feather))
+void sculpt_cache_calc_brushdata_symm(
+ StrokeCache *cache, const char symm,
+ const char axis, const float angle)
{
- (void)sd; /* unused */
-
flip_v3_v3(cache->location, cache->true_location, symm);
+ flip_v3_v3(cache->last_location, cache->true_last_location, symm);
flip_v3_v3(cache->grab_delta_symmetry, cache->grab_delta, symm);
flip_v3_v3(cache->view_normal, cache->true_view_normal, symm);
@@ -3792,7 +3806,7 @@ static void do_tiled(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings
static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups,
BrushActionFunc action,
const char symm, const int axis,
- const float feather)
+ const float UNUSED(feather))
{
SculptSession *ss = ob->sculpt;
int i;
@@ -3800,7 +3814,7 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPain
for (i = 1; i < sd->radial_symm[axis - 'X']; ++i) {
const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
ss->cache->radial_symmetry_pass = i;
- calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather);
+ sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
do_tiled(sd, ob, brush, ups, action);
}
}
@@ -3818,8 +3832,9 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
multires_stitch_grids(ob);
}
-static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob,
- BrushActionFunc action, UnifiedPaintSettings *ups)
+static void do_symmetrical_brush_actions(
+ Sculpt *sd, Object *ob,
+ BrushActionFunc action, UnifiedPaintSettings *ups)
{
Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
@@ -3838,7 +3853,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob,
cache->mirror_symmetry_pass = i;
cache->radial_symmetry_pass = 0;
- calc_brushdata_symm(sd, cache, i, 0, 0, feather);
+ sculpt_cache_calc_brushdata_symm(cache, i, 0, 0);
do_tiled(sd, ob, brush, ups, action);
do_radial_symmetry(sd, ob, brush, ups, action, i, 'X', feather);
@@ -3949,7 +3964,7 @@ static const char *sculpt_tool_name(Sculpt *sd)
* Operator for applying a stroke (various attributes including mouse path)
* using the current brush. */
-static void sculpt_cache_free(StrokeCache *cache)
+void sculpt_cache_free(StrokeCache *cache)
{
if (cache->dial)
MEM_freeN(cache->dial);
@@ -4188,7 +4203,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
/* compute 3d coordinate at same z from original location + mouse */
mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location);
- ED_view3d_win_to_3d(cache->vc->ar, loc, mouse, grab_location);
+ ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->ar, loc, mouse, grab_location);
/* compute delta to move verts by */
if (!cache->first_time) {
@@ -4212,7 +4227,6 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
sub_v3_v3v3(cache->grab_delta, grab_location,
cache->old_grab_location);
}
-
invert_m4_m4(imat, ob->obmat);
mul_mat3_m4_v3(imat, cache->grab_delta);
break;
@@ -4222,6 +4236,10 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
zero_v3(cache->grab_delta);
}
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(cache->grab_delta, cache->grab_delta, ss->cache->true_view_normal);
+ }
+
copy_v3_v3(cache->old_grab_location, grab_location);
if (tool == SCULPT_TOOL_GRAB)
@@ -4399,21 +4417,6 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob)
}
}
-typedef struct {
- SculptSession *ss;
- const float *ray_start, *ray_normal;
- bool hit;
- float dist;
- bool original;
-} SculptRaycastData;
-
-typedef struct {
- const float *ray_start, *ray_normal;
- bool hit;
- float dist;
- float detail;
-} SculptDetailRaycastData;
-
static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
{
if (BKE_pbvh_node_get_tmin(node) < *tmin) {
@@ -4434,10 +4437,40 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
}
if (BKE_pbvh_node_raycast(srd->ss->pbvh, node, origco, use_origco,
- srd->ray_start, srd->ray_normal, &srd->dist))
+ srd->ray_start, srd->ray_normal, &srd->depth))
{
srd->hit = 1;
- *tmin = srd->dist;
+ *tmin = srd->depth;
+ }
+ }
+}
+
+static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *tmin)
+{
+ if (BKE_pbvh_node_get_tmin(node) < *tmin) {
+ SculptFindNearestToRayData *srd = data_v;
+ float (*origco)[3] = NULL;
+ bool use_origco = false;
+
+ if (srd->original && srd->ss->cache) {
+ if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) {
+ use_origco = true;
+ }
+ else {
+ /* intersect with coordinates from before we started stroke */
+ SculptUndoNode *unode = sculpt_undo_get_node(node);
+ origco = (unode) ? unode->co : NULL;
+ use_origco = origco ? true : false;
+ }
+ }
+
+ if (BKE_pbvh_node_find_nearest_to_ray(
+ srd->ss->pbvh, node, origco, use_origco,
+ srd->ray_start, srd->ray_normal,
+ &srd->depth, &srd->dist_sq_to_ray))
+ {
+ srd->hit = 1;
+ *tmin = srd->dist_sq_to_ray;
}
}
}
@@ -4447,10 +4480,10 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
if (BKE_pbvh_node_get_tmin(node) < *tmin) {
SculptDetailRaycastData *srd = data_v;
if (BKE_pbvh_bmesh_node_raycast_detail(node, srd->ray_start, srd->ray_normal,
- &srd->dist, &srd->detail))
+ &srd->depth, &srd->detail))
{
srd->hit = 1;
- *tmin = srd->dist;
+ *tmin = srd->depth;
}
}
}
@@ -4497,8 +4530,7 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
Object *ob;
SculptSession *ss;
StrokeCache *cache;
- float ray_start[3], ray_end[3], ray_normal[3], dist;
- SculptRaycastData srd;
+ float ray_start[3], ray_end[3], ray_normal[3], depth;
bool original;
ViewContext vc;
@@ -4512,23 +4544,58 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
sculpt_stroke_modifiers_check(C, ob);
- dist = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
- srd.original = original;
- srd.ss = ob->sculpt;
- srd.hit = 0;
- srd.ray_start = ray_start;
- srd.ray_normal = ray_normal;
- srd.dist = dist;
+ bool hit = false;
+ {
+ SculptRaycastData srd = {
+ .original = original,
+ .ss = ob->sculpt,
+ .hit = 0,
+ .ray_start = ray_start,
+ .ray_normal = ray_normal,
+ .depth = depth,
+ };
+ BKE_pbvh_raycast(
+ ss->pbvh, sculpt_raycast_cb, &srd,
+ ray_start, ray_normal, srd.original);
+ if (srd.hit) {
+ hit = true;
+ copy_v3_v3(out, ray_normal);
+ mul_v3_fl(out, srd.depth);
+ add_v3_v3(out, ray_start);
+ }
+ }
- BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd,
- ray_start, ray_normal, srd.original);
+ if (hit == false) {
+ const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
+ if (ELEM(brush->falloff_shape, PAINT_FALLOFF_SHAPE_TUBE)) {
+ SculptFindNearestToRayData srd = {
+ .original = original,
+ .ss = ob->sculpt,
+ .hit = 0,
+ .ray_start = ray_start,
+ .ray_normal = ray_normal,
+ .depth = FLT_MAX,
+ .dist_sq_to_ray = FLT_MAX,
+ };
+ BKE_pbvh_find_nearest_to_ray(
+ ss->pbvh, sculpt_find_nearest_to_ray_cb, &srd,
+ ray_start, ray_normal, srd.original);
+ if (srd.hit) {
+ hit = true;
+ copy_v3_v3(out, ray_normal);
+ mul_v3_fl(out, srd.depth);
+ add_v3_v3(out, ray_start);
+ }
+ }
+ }
- copy_v3_v3(out, ray_normal);
- mul_v3_fl(out, srd.dist);
- add_v3_v3(out, ray_start);
+ if (cache && hit) {
+ copy_v3_v3(cache->true_location, out);
+ }
- return srd.hit;
+ return hit;
}
static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
@@ -4657,8 +4724,11 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
const float mouse[2])
{
/* Don't start the stroke until mouse goes over the mesh.
- * note: mouse will only be null when re-executing the saved stroke. */
- if (!mouse || over_mesh(C, op, mouse[0], mouse[1])) {
+ * note: mouse will only be null when re-executing the saved stroke.
+ * We have exception for 'exec' strokes since they may not set 'mouse', only 'location', see: T52195. */
+ if (((op->flag & OP_IS_INVOKE) == 0) ||
+ (mouse == NULL) || over_mesh(C, op, mouse[0], mouse[1]))
+ {
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -4755,6 +4825,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
if (ss->cache) {
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Brush *brush = BKE_paint_brush(&sd->paint);
+ BLI_assert(brush == ss->cache->brush); /* const, so we shouldn't change. */
ups->draw_inverted = false;
sculpt_stroke_modifiers_check(C, ob);
@@ -4765,11 +4836,10 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
brush->mask_tool = ss->cache->saved_mask_brush_tool;
}
else {
- Paint *p = &sd->paint;
- BKE_brush_size_set(scene, ss->cache->brush, ss->cache->saved_smooth_size);
+ BKE_brush_size_set(scene, brush, ss->cache->saved_smooth_size);
brush = (Brush *)BKE_libblock_find_name(ID_BR, ss->cache->saved_active_brush_name);
if (brush) {
- BKE_paint_brush_set(p, brush);
+ BKE_paint_brush_set(&sd->paint, brush);
}
}
}
@@ -5362,8 +5432,12 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
if (mmd)
multires_force_update(ob);
- if (flush_recalc || (ob->sculpt && ob->sculpt->bm))
+ /* Always for now, so leaving sculpt mode always ensures scene is in
+ * a consistent state.
+ */
+ if (true || flush_recalc || (ob->sculpt && ob->sculpt->bm)) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
/* Dynamic topology must be disabled before exiting sculpt
@@ -5524,7 +5598,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
float size;
- float bb_min[3], bb_max[3];
+ float bb_min[3], bb_max[3], center[3], dim[3];
int i, totnodes;
PBVHNode **nodes;
@@ -5536,11 +5610,12 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
for (i = 0; i < totnodes; i++) {
BKE_pbvh_node_mark_topology_update(nodes[i]);
}
- /* get the bounding box, store the size to bb_max and center (zero) to bb_min */
+ /* get the bounding box, it's center and size */
BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max);
- sub_v3_v3(bb_max, bb_min);
- zero_v3(bb_min);
- size = max_fff(bb_max[0], bb_max[1], bb_max[2]);
+ add_v3_v3v3(center, bb_min, bb_max);
+ mul_v3_fl(center, 0.5f);
+ sub_v3_v3v3(dim, bb_max, bb_min);
+ size = max_fff(dim[0], dim[1], dim[2]);
/* update topology size */
BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail);
@@ -5550,7 +5625,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
while (BKE_pbvh_bmesh_update_topology(
ss->pbvh, PBVH_Collapse | PBVH_Subdivide,
- bb_min, NULL, size))
+ center, NULL, size, false, false))
{
for (i = 0; i < totnodes; i++)
BKE_pbvh_node_mark_topology_update(nodes[i]);
@@ -5586,7 +5661,7 @@ static void sample_detail(bContext *C, int ss_co[2])
ViewContext vc;
Object *ob;
Sculpt *sd;
- float ray_start[3], ray_end[3], ray_normal[3], dist;
+ float ray_start[3], ray_end[3], ray_normal[3], depth;
SculptDetailRaycastData srd;
float mouse[2] = {ss_co[0], ss_co[1]};
view3d_set_viewcontext(C, &vc);
@@ -5596,12 +5671,12 @@ static void sample_detail(bContext *C, int ss_co[2])
sculpt_stroke_modifiers_check(C, ob);
- dist = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, false);
+ depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, false);
srd.hit = 0;
srd.ray_start = ray_start;
srd.ray_normal = ray_normal;
- srd.dist = dist;
+ srd.depth = depth;
srd.detail = sd->constant_detail;
BKE_pbvh_raycast(ob->sculpt->pbvh, sculpt_raycast_detail_cb, &srd,
@@ -5694,11 +5769,11 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
WM_operator_properties_create_ptr(&props_ptr, ot);
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
- set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
- RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail");
+ set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0);
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail_resolution");
}
else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
- set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
+ set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0);
RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
}
else {
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 108fe3532e3..aaea13ce5d0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -38,12 +38,15 @@
#include "DNA_key_types.h"
#include "BLI_bitmap.h"
+#include "BLI_threads.h"
+
#include "BKE_pbvh.h"
struct bContext;
struct KeyBlock;
struct Object;
struct SculptUndoNode;
+struct SculptOrigVertData;
int sculpt_mode_poll(struct bContext *C);
int sculpt_mode_poll_view3d(struct bContext *C);
@@ -52,12 +55,12 @@ int sculpt_poll(struct bContext *C);
int sculpt_poll_view3d(struct bContext *C);
/* Stroke */
-bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]);
+bool sculpt_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]);
/* Dynamic topology */
void sculpt_pbvh_clear(Object *ob);
void sculpt_dyntopo_node_layers_add(struct SculptSession *ss);
-void sculpt_update_after_dynamic_topology_toggle(bContext *C);
+void sculpt_update_after_dynamic_topology_toggle(struct bContext *C);
void sculpt_dynamic_topology_enable(struct bContext *C);
void sculpt_dynamic_topology_disable(struct bContext *C,
struct SculptUndoNode *unode);
@@ -115,6 +118,227 @@ typedef struct SculptUndoNode {
char shapeName[sizeof(((KeyBlock *)0))->name];
} SculptUndoNode;
+/* Factor of brush to have rake point following behind
+* (could be configurable but this is reasonable default). */
+#define SCULPT_RAKE_BRUSH_FACTOR 0.25f
+
+struct SculptRakeData {
+ float follow_dist;
+ float follow_co[3];
+};
+
+/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */
+typedef struct SculptThreadedTaskData {
+ struct bContext *C;
+ struct Sculpt *sd;
+ struct Object *ob;
+ const struct Brush *brush;
+ struct PBVHNode **nodes;
+ int totnode;
+
+ struct VPaint *vp;
+ struct VPaintData *vpd;
+ struct WPaintData *wpd;
+ struct WeightPaintInfo *wpi;
+ unsigned int *lcol;
+ struct Mesh *me;
+ /* For passing generic params. */
+ void *custom_data;
+
+
+ /* Data specific to some callbacks. */
+ /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out
+ * what it is, and memory overhead is ridiculous anyway... */
+ float flippedbstrength;
+ float angle;
+ float strength;
+ bool smooth_mask;
+ bool has_bm_orco;
+
+ struct SculptProjectVector *spvc;
+ float *offset;
+ float *grab_delta;
+ float *cono;
+ float *area_no;
+ float *area_no_sp;
+ float *area_co;
+ float(*mat)[4];
+ float(*vertCos)[3];
+
+ /* 0=towards view, 1=flipped */
+ float(*area_cos)[3];
+ float(*area_nos)[3];
+ int *count;
+
+ ThreadMutex mutex;
+
+} SculptThreadedTaskData;
+
+/*************** Brush testing declarations ****************/
+typedef struct SculptBrushTest {
+ float radius_squared;
+ float location[3];
+ float dist;
+ int mirror_symmetry_pass;
+
+ /* For circle (not sphere) projection. */
+ float plane_view[4];
+
+ /* Some tool code uses a plane for it's calculateions. */
+ float plane_tool[4];
+
+ /* View3d clipping - only set rv3d for clipping */
+ struct RegionView3D *clip_rv3d;
+} SculptBrushTest;
+
+typedef bool (*SculptBrushTestFn)(SculptBrushTest *test, const float co[3]);
+
+typedef struct {
+ struct Sculpt *sd;
+ struct SculptSession *ss;
+ float radius_squared;
+ bool original;
+} SculptSearchSphereData;
+
+typedef struct {
+ struct Sculpt *sd;
+ struct SculptSession *ss;
+ float radius_squared;
+ bool original;
+ struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
+} SculptSearchCircleData;
+
+void sculpt_brush_test_init(struct SculptSession *ss, SculptBrushTest *test);
+bool sculpt_brush_test_sphere(SculptBrushTest *test, const float co[3]);
+bool sculpt_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]);
+bool sculpt_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3]);
+bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4]);
+bool sculpt_brush_test_circle_sq(SculptBrushTest *test, const float co[3]);
+bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v);
+bool sculpt_search_circle_cb(PBVHNode *node, void *data_v);
+
+SculptBrushTestFn sculpt_brush_test_init_with_falloff_shape(
+ SculptSession *ss, SculptBrushTest *test, char falloff_shape);
+const float *sculpt_brush_frontface_normal_from_falloff_shape(
+ SculptSession *ss, char falloff_shape);
+
+float tex_strength(
+ struct SculptSession *ss, const struct Brush *br,
+ const float point[3],
+ const float len,
+ const short vno[3],
+ const float fno[3],
+ const float mask,
+ const int thread_id);
+
+/* just for vertex paint. */
+void sculpt_pbvh_calc_area_normal(
+ const struct Brush *brush, Object *ob,
+ PBVHNode **nodes, int totnode,
+ bool use_threading,
+ float r_area_no[3]);
+
+/* Cache stroke properties. Used because
+* RNA property lookup isn't particularly fast.
+*
+* For descriptions of these settings, check the operator properties.
+*/
+
+typedef struct StrokeCache {
+ /* Invariants */
+ float initial_radius;
+ float scale[3];
+ int flag;
+ float clip_tolerance[3];
+ float initial_mouse[2];
+
+ /* Variants */
+ float radius;
+ float radius_squared;
+ float true_location[3];
+ float true_last_location[3];
+ float location[3];
+ float last_location[3];
+ bool is_last_valid;
+
+ bool pen_flip;
+ bool invert;
+ float pressure;
+ float mouse[2];
+ float bstrength;
+ float normal_weight; /* from brush (with optional override) */
+
+ /* The rest is temporary storage that isn't saved as a property */
+
+ bool first_time; /* Beginning of stroke may do some things special */
+
+ /* from ED_view3d_ob_project_mat_get() */
+ float projection_mat[4][4];
+
+ /* Clean this up! */
+ struct ViewContext *vc;
+ const struct Brush *brush;
+
+ float special_rotation;
+ float grab_delta[3], grab_delta_symmetry[3];
+ float old_grab_location[3], orig_grab_location[3];
+
+ /* screen-space rotation defined by mouse motion */
+ float rake_rotation[4], rake_rotation_symmetry[4];
+ bool is_rake_rotation_valid;
+ struct SculptRakeData rake_data;
+
+ /* Symmetry index between 0 and 7 bit combo 0 is Brush only;
+ * 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
+ int symmetry;
+ int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
+ float true_view_normal[3];
+ float view_normal[3];
+
+ /* sculpt_normal gets calculated by calc_sculpt_normal(), then the
+ * sculpt_normal_symm gets updated quickly with the usual symmetry
+ * transforms */
+ float sculpt_normal[3];
+ float sculpt_normal_symm[3];
+
+ /* Used for area texture mode, local_mat gets calculated by
+ * calc_brush_local_mat() and used in tex_strength(). */
+ float brush_local_mat[4][4];
+
+ float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */
+ int tile_pass;
+
+ float last_center[3];
+ int radial_symmetry_pass;
+ float symm_rot_mat[4][4];
+ float symm_rot_mat_inv[4][4];
+ bool original;
+ float anchored_location[3];
+
+ float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
+ struct Dial *dial;
+
+ char saved_active_brush_name[MAX_ID_NAME];
+ char saved_mask_brush_tool;
+ int saved_smooth_size; /* smooth tool copies the size of the current tool */
+ bool alt_smooth;
+
+ float plane_trim_squared;
+
+ bool supports_gravity;
+ float true_gravity_direction[3];
+ float gravity_direction[3];
+
+ rcti previous_r; /* previous redraw rectangle */
+ rcti current_r; /* current redraw rectangle */
+
+} StrokeCache;
+
+void sculpt_cache_calc_brushdata_symm(
+ StrokeCache *cache, const char symm,
+ const char axis, const float angle);
+void sculpt_cache_free(StrokeCache *cache);
+
SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node);
void sculpt_undo_push_begin(const char *name);
@@ -124,6 +348,8 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]);
void sculpt_update_object_bounding_box(struct Object *ob);
+bool sculpt_get_redraw_rect(struct ARegion *ar, struct RegionView3D *rv3d, Object *ob, rcti *rect);
+
#define SCULPT_THREADED_LIMIT 4
#endif
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 432918f0e37..e273d3a40f0 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -383,6 +383,8 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS,
accuracy, filename, specs, container, codec, bitrate);
+ BKE_sound_reset_scene_specs(scene);
+
if (result) {
BKE_report(op->reports, RPT_ERROR, result);
return OPERATOR_CANCELLED;
@@ -668,7 +670,7 @@ static void SOUND_OT_mixdown(wmOperatorType *ot)
/* identifiers */
ot->name = "Mixdown";
- ot->description = "Mixes the scene's audio to a sound file";
+ ot->description = "Mix the scene's audio to a sound file";
ot->idname = "SOUND_OT_mixdown";
/* api callbacks */
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 9fc96e06299..0764f586de9 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -170,6 +170,8 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
unsigned char col1a[3], col2a[3];
unsigned char col1b[3], col2b[3];
+ const bool show_group_colors = !(saction->flag & SACTION_NODRAWGCOLORS);
+
/* get theme colors */
UI_GetThemeColor3ubv(TH_BACK, col2);
@@ -247,8 +249,36 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
}
case ANIMTYPE_GROUP:
{
- if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
- else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
+ bActionGroup *agrp = ale->data;
+ if (show_group_colors && agrp->customCol) {
+ if (sel) {
+ unsigned char *cp = (unsigned char *)agrp->cs.select;
+ glColor4ub(cp[0], cp[1], cp[2], 0x45);
+ }
+ else {
+ unsigned char *cp = (unsigned char *)agrp->cs.solid;
+ glColor4ub(cp[0], cp[1], cp[2], 0x1D);
+ }
+ }
+ else {
+ if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
+ else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
+ }
+ break;
+ }
+ case ANIMTYPE_FCURVE:
+ {
+ FCurve *fcu = ale->data;
+ if (show_group_colors && fcu->grp && fcu->grp->customCol) {
+ unsigned char *cp = (unsigned char *)fcu->grp->cs.active;
+
+ if (sel) glColor4ub(cp[0], cp[1], cp[2], 0x65);
+ else glColor4ub(cp[0], cp[1], cp[2], 0x0B);
+ }
+ else {
+ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
+ else glColor4ub(col2[0], col2[1], col2[2], 0x22);
+ }
break;
}
default:
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index f8db35e2311..a9920389980 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -1522,7 +1522,7 @@ static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
/* set the new current frame value, based on the average time */
if (ked.i1) {
Scene *scene = ac.scene;
- CFRA = iroundf(ked.f1 / ked.i1);
+ CFRA = round_fl_to_int(ked.f1 / ked.i1);
SUBFRA = 0.f;
}
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 553be0ad290..17edbc6cc1d 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -262,6 +262,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
{
/* loop over data selecting */
switch (ale->type) {
+#if 0 /* XXXX: Keyframes are not currently shown here */
case ANIMTYPE_GPDATABLOCK:
{
bGPdata *gpd = ale->data;
@@ -271,6 +272,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
}
break;
}
+#endif
case ANIMTYPE_GPLAYER:
ED_gplayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode);
break;
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 671d6bb083e..5cde224b7dc 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -337,7 +337,7 @@ static void action_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(
}
break;
case NC_GPENCIL:
- if (wmn->action == NA_RENAME)
+ if (ELEM(wmn->action, NA_RENAME, NA_SELECTED))
ED_region_tag_redraw(ar);
break;
case NC_ID:
@@ -407,10 +407,15 @@ static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
- if (wmn->action == NA_EDITED) {
- /* only handle this event in GPencil mode for performance considerations */
- if (saction->mode == SACTCONT_GPENCIL)
+ /* only handle these events in GPencil mode for performance considerations */
+ if (saction->mode == SACTCONT_GPENCIL) {
+ if (wmn->action == NA_EDITED) {
ED_area_tag_redraw(sa);
+ }
+ else if (wmn->action == NA_SELECTED) {
+ saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
+ ED_area_tag_refresh(sa);
+ }
}
break;
case NC_ANIMATION:
@@ -619,13 +624,17 @@ static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, I
{
SpaceAction *sact = (SpaceAction *)slink;
- if (!ELEM(GS(old_id->name), ID_GR)) {
- return;
+ if ((ID *)sact->action == old_id) {
+ sact->action = (bAction *)new_id;
}
if ((ID *)sact->ads.filter_grp == old_id) {
sact->ads.filter_grp = (Group *)new_id;
}
+ if ((ID *)sact->ads.source == old_id) {
+ sact->ads.source = new_id;
+ }
+
}
/* only called once, from space/spacetypes.c */
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 72de7e5c81c..1d67ac620b0 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -470,7 +470,7 @@ void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts)
}
else {
/* set one user as active based on active index */
- if (ct->index == BLI_listbase_count_ex(&ct->users, ct->index + 1))
+ if (ct->index >= BLI_listbase_count_ex(&ct->users, ct->index + 1))
ct->index = 0;
ct->user = BLI_findlink(&ct->users, ct->index);
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 695d04d3850..a71b2baa96f 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -365,9 +365,11 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int
static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
{
+#define MAX_STATIC_PATH 64
int count = sc->path_length;
int i, a, b, curindex = -1;
- float path[102][2];
+ float path_static[(MAX_STATIC_PATH + 1) * 2][2];
+ float (*path)[2];
int tiny = sc->flag & SC_SHOW_TINY_MARKER, framenr, start_frame;
MovieTrackingMarker *marker;
@@ -380,6 +382,13 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin
if (marker->framenr != framenr || marker->flag & MARKER_DISABLED)
return;
+ if (count < MAX_STATIC_PATH) {
+ path = path_static;
+ }
+ else {
+ path = MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path");
+ }
+
a = count;
i = framenr - 1;
while (i >= framenr - count) {
@@ -470,6 +479,11 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin
glVertex2f(path[i][0], path[i][1]);
}
glEnd();
+
+ if (path != path_static) {
+ MEM_freeN(path);
+ }
+#undef MAX_STATIC_PATH
}
static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 14d0f909d23..59dd755173f 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -259,11 +259,9 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale
return NULL;
}
-/* Returns color in the display space, matching ED_space_image_color_sample(). */
-bool ED_space_clip_color_sample(Scene *scene, SpaceClip *sc, ARegion *ar, int mval[2], float r_col[3])
+/* Returns color in linear space, matching ED_space_image_color_sample(). */
+bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r_col[3])
{
- const char *display_device = scene->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
ImBuf *ibuf;
float fx, fy, co[2];
bool ret = false;
@@ -299,11 +297,7 @@ bool ED_space_clip_color_sample(Scene *scene, SpaceClip *sc, ARegion *ar, int mv
ret = true;
}
}
-
- if (ret) {
- IMB_colormanagement_scene_linear_to_display_v3(r_col, display);
- }
-
+
IMB_freeImBuf(ibuf);
return ret;
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 9430ee626ba..970eae0ad14 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -941,7 +941,7 @@ static int frame_from_event(bContext *C, const wmEvent *event)
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
- framenr = iroundf(viewx);
+ framenr = round_fl_to_int(viewx);
}
return framenr;
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 547c2fba66f..e901b9f8026 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -72,7 +72,7 @@ void clip_graph_tracking_values_iterate_track(
BKE_movieclip_get_size(clip, &sc->user, &width, &height);
for (coord = 0; coord < 2; coord++) {
- int i, prevfra = 0;
+ int i, prevfra = track->markers[0].framenr;
bool open = false;
float prevval = 0.0f;
@@ -179,6 +179,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
bool has_bundle = false;
char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];
+ const bool used_for_stabilization = (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT));
if (track == act_track)
tracking->act_track = NULL;
@@ -200,7 +201,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
- if (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)) {
+ if (used_for_stabilization) {
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 05e69968e35..58930fa2cf2 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -337,7 +337,7 @@ static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
switch (wmn->data) {
case ND_FRAME:
clip_scopes_tag_refresh(sa);
- /* fall-through */
+ ATTR_FALLTHROUGH;
case ND_FRAME_RANGE:
ED_area_tag_redraw(sa);
@@ -821,6 +821,7 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
#endif
}
+/* DO NOT make this static, this hides the symbol and breaks API generation script. */
const char *clip_context_dir[] = {"edit_movieclip", "edit_mask", NULL};
static int clip_context(const bContext *C, const char *member, bContextDataResult *result)
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index d28cbe5fb1d..56c240c3d20 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -875,8 +875,7 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) {
data->accurate = event->val == KM_PRESS;
}
-
- /* fall-through */
+ ATTR_FALLTHROUGH;
case MOUSEMOVE:
mdelta[0] = event->mval[0] - data->mval[0];
mdelta[1] = event->mval[1] - data->mval[1];
@@ -1534,7 +1533,8 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
update_stabilization = true;
if ((act_track->flag & TRACK_USE_2D_STAB) == 0) {
act_track->flag |= TRACK_USE_2D_STAB;
- } else {
+ }
+ else {
stab->tot_track--;
}
BLI_assert(0 <= stab->tot_track);
@@ -1543,7 +1543,8 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
update_stabilization = true;
if ((act_track->flag & TRACK_USE_2D_STAB_ROT) == 0) {
act_track->flag |= TRACK_USE_2D_STAB_ROT;
- } else {
+ }
+ else {
stab->tot_rot_track--;
}
BLI_assert(0 <= stab->tot_rot_track);
diff --git a/source/blender/editors/space_clip/tracking_ops_plane.c b/source/blender/editors/space_clip/tracking_ops_plane.c
index 4332f3ea765..aa8518befaa 100644
--- a/source/blender/editors/space_clip/tracking_ops_plane.c
+++ b/source/blender/editors/space_clip/tracking_ops_plane.c
@@ -301,8 +301,7 @@ static int slide_plane_marker_modal(bContext *C,
if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) {
data->accurate = event->val == KM_PRESS;
}
-
- /* fall-through */
+ ATTR_FALLTHROUGH;
case MOUSEMOVE:
mdelta[0] = event->mval[0] - data->previous_mval[0];
mdelta[1] = event->mval[1] - data->previous_mval[1];
diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c
index 368cbeaf955..0dd0ee8c7d4 100644
--- a/source/blender/editors/space_clip/tracking_ops_track.c
+++ b/source/blender/editors/space_clip/tracking_ops_track.c
@@ -165,7 +165,7 @@ static int track_markers_initjob(bContext *C,
track_init_markers(sc, clip, framenr, &frames_limit);
- tmj->sfra = ED_space_clip_get_clip_frame_number(sc);
+ tmj->sfra = framenr;
tmj->clip = clip;
tmj->backwards = backwards;
@@ -176,6 +176,7 @@ static int track_markers_initjob(bContext *C,
else {
tmj->efra = EFRA;
}
+ tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra);
}
else {
if (backwards) {
@@ -196,8 +197,6 @@ static int track_markers_initjob(bContext *C,
}
}
- tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra);
-
if (settings->speed != TRACKING_SPEED_FASTEST) {
tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f;
@@ -212,7 +211,7 @@ static int track_markers_initjob(bContext *C,
}
}
- tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards, 1);
+ tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards, true);
clip->tracking_context = tmj->context;
@@ -310,6 +309,7 @@ static void track_markers_endjob(void *tmv)
static void track_markers_freejob(void *tmv)
{
TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
+ tmj->clip->tracking_context = NULL;
BKE_autotrack_context_free(tmj->context);
MEM_freeN(tmj);
}
diff --git a/source/blender/editors/space_console/console_intern.h b/source/blender/editors/space_console/console_intern.h
index 5b016b77e9f..f523cf0d476 100644
--- a/source/blender/editors/space_console/console_intern.h
+++ b/source/blender/editors/space_console/console_intern.h
@@ -70,6 +70,6 @@ void CONSOLE_OT_select_set(struct wmOperatorType *ot);
void CONSOLE_OT_select_word(struct wmOperatorType *ot);
enum { LINE_BEGIN, LINE_END, PREV_CHAR, NEXT_CHAR, PREV_WORD, NEXT_WORD };
-enum { DEL_ALL, DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL };
+enum { DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL };
#endif /* __CONSOLE_INTERN_H__ */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index b7228f634bf..22c1214d928 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1302,7 +1302,6 @@ void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
if (BLI_is_dir(filepath)) {
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
- sfile->params->file[0] = '\0';
}
else {
if ((sfile->params->flag & FILE_DIRSEL_ONLY) == 0) {
@@ -2204,7 +2203,7 @@ static int file_rename_poll(bContext *C)
poll = false;
}
else {
- char dir[FILE_MAX];
+ char dir[FILE_MAX_LIBEXTRA];
if (filelist_islibrary(sfile->files, dir, NULL)) {
poll = false;
}
@@ -2236,7 +2235,7 @@ static int file_delete_poll(bContext *C)
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile && sfile->params) {
- char dir[FILE_MAX];
+ char dir[FILE_MAX_LIBEXTRA];
int numfiles = filelist_files_ensure(sfile->files);
int i;
int num_selected = 0;
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 83469a48165..d670af59bc9 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -277,9 +277,10 @@ typedef struct FileListFilter {
/* FileListFilter.flags */
enum {
- FLF_HIDE_DOT = 1 << 0,
- FLF_HIDE_PARENT = 1 << 1,
- FLF_HIDE_LIB_DIR = 1 << 2,
+ FLF_DO_FILTER = 1 << 0,
+ FLF_HIDE_DOT = 1 << 1,
+ FLF_HIDE_PARENT = 1 << 2,
+ FLF_HIDE_LIB_DIR = 1 << 3,
};
typedef struct FileList {
@@ -594,24 +595,27 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root)
{
bool is_filtered = !is_hidden_file(file->relpath, filter);
- if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relpath)) {
- if (file->typeflag & FILE_TYPE_DIR) {
- if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
- if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
- is_filtered = false;
+ if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ /* We only check for types if some type are enabled in filtering. */
+ if (filter->filter) {
+ if (file->typeflag & FILE_TYPE_DIR) {
+ if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
+ if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
+ is_filtered = false;
+ }
+ }
+ else {
+ if (!(filter->filter & FILE_TYPE_FOLDER)) {
+ is_filtered = false;
+ }
}
}
else {
- if (!(filter->filter & FILE_TYPE_FOLDER)) {
+ if (!(file->typeflag & filter->filter)) {
is_filtered = false;
}
}
}
- else {
- if (!(file->typeflag & filter->filter)) {
- is_filtered = false;
- }
- }
if (is_filtered && (filter->filter_search[0] != '\0')) {
if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
is_filtered = false;
@@ -631,28 +635,31 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis
if (BLO_library_path_explode(path, dir, &group, &name)) {
is_filtered = !is_hidden_file(file->relpath, filter);
- if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relpath)) {
- if (file->typeflag & FILE_TYPE_DIR) {
- if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
- if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
- is_filtered = false;
+ if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ /* We only check for types if some type are enabled in filtering. */
+ if (filter->filter || filter->filter_id) {
+ if (file->typeflag & FILE_TYPE_DIR) {
+ if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
+ if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
+ is_filtered = false;
+ }
}
- }
- else {
- if (!(filter->filter & FILE_TYPE_FOLDER)) {
- is_filtered = false;
+ else {
+ if (!(filter->filter & FILE_TYPE_FOLDER)) {
+ is_filtered = false;
+ }
}
}
- }
- if (is_filtered && group) {
- if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
- is_filtered = false;
- }
- else {
- unsigned int filter_id = groupname_to_filter_id(group);
- if (!(filter_id & filter->filter_id)) {
+ if (is_filtered && group) {
+ if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
is_filtered = false;
}
+ else {
+ unsigned int filter_id = groupname_to_filter_id(group);
+ if (!(filter_id & filter->filter_id)) {
+ is_filtered = false;
+ }
+ }
}
}
if (is_filtered && (filter->filter_search[0] != '\0')) {
@@ -729,12 +736,17 @@ void filelist_filter(FileList *filelist)
MEM_freeN(filtered_tmp);
}
-void filelist_setfilter_options(FileList *filelist, const bool hide_dot, const bool hide_parent,
+void filelist_setfilter_options(FileList *filelist, const bool do_filter,
+ const bool hide_dot, const bool hide_parent,
const unsigned int filter, const unsigned int filter_id,
const char *filter_glob, const char *filter_search)
{
bool update = false;
+ if (((filelist->filter_data.flags & FLF_DO_FILTER) != 0) != (do_filter != 0)) {
+ filelist->filter_data.flags ^= FLF_DO_FILTER;
+ update = true;
+ }
if (((filelist->filter_data.flags & FLF_HIDE_DOT) != 0) != (hide_dot != 0)) {
filelist->filter_data.flags ^= FLF_HIDE_DOT;
update = true;
@@ -1104,7 +1116,10 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source);
IMB_thumb_path_unlock(preview->path);
- preview->flags = 0; /* Used to tell free func to not free anything! */
+ /* Used to tell free func to not free anything.
+ * Note that we do not care about cas result here,
+ * we only want value attribution itself to be atomic (and memory barier).*/
+ atomic_cas_uint32(&preview->flags, preview->flags, 0);
BLI_thread_queue_push(cache->previews_done, preview);
// printf("%s: End (%d)...\n", __func__, threadid);
@@ -1964,7 +1979,7 @@ int ED_path_extension_type(const char *path)
else if (BLI_testextensie(path, ".py")) {
return FILE_TYPE_PYSCRIPT;
}
- else if (BLI_testextensie_n(path, ".txt", ".glsl", ".osl", ".data", NULL)) {
+ else if (BLI_testextensie_n(path, ".txt", ".glsl", ".osl", ".data", ".pov", ".ini", ".mcr", ".inc", NULL)) {
return FILE_TYPE_TEXT;
}
else if (BLI_testextensie_n(path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", NULL)) {
@@ -1979,9 +1994,7 @@ int ED_path_extension_type(const char *path)
else if (BLI_testextensie(path, ".abc")) {
return FILE_TYPE_ALEMBIC;
}
- else if (BLI_testextensie_array(path, imb_ext_image) ||
- (G.have_quicktime && BLI_testextensie_array(path, imb_ext_image_qt)))
- {
+ else if (BLI_testextensie_array(path, imb_ext_image)) {
return FILE_TYPE_IMAGE;
}
else if (BLI_testextensie(path, ".ogg")) {
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index f4304681780..4e9c1e0dd1d 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -68,7 +68,8 @@ int folderlist_clear_next(struct SpaceFile *sfile);
void filelist_setsorting(struct FileList *filelist, const short sort);
void filelist_sort(struct FileList *filelist);
-void filelist_setfilter_options(struct FileList *filelist, const bool hide_dot, const bool hide_parent,
+void filelist_setfilter_options(struct FileList *filelist, const bool do_filter,
+ const bool hide_dot, const bool hide_parent,
const unsigned int filter, const unsigned int filter_id,
const char *filter_glob, const char *filter_search);
void filelist_filter(struct FileList *filelist);
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 631ff06a77a..ee0ec3fda39 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -48,9 +48,6 @@
#ifdef WIN32
# include <windows.h> /* need to include windows.h so _WIN32_IE is defined */
-# ifndef _WIN32_IE
-# define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */
-# endif
# include <shlobj.h> /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff
* because 'near' is disabled through BLI_windstuff */
# include "BLI_winstuff.h"
@@ -169,12 +166,15 @@ void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path)
static void fsmenu_entry_generate_name(struct FSMenuEntry *fsentry, char *name, size_t name_size)
{
- char temp[FILE_MAX];
+ int offset = 0;
+ int len = name_size;
- BLI_strncpy(temp, fsentry->path, FILE_MAX);
- BLI_add_slash(temp);
- BLI_getlastdir(temp, name, name_size);
- BLI_del_slash(name);
+ if (BLI_path_name_at_index(fsentry->path, -1, &offset, &len)) {
+ /* use as size */
+ len += 1;
+ }
+
+ BLI_strncpy(name, &fsentry->path[offset], MIN2(len, name_size));
if (!name[0]) {
name[0] = '/';
name[1] = '\0';
@@ -537,28 +537,22 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* Finally get user favorite places */
if (read_bookmarks) {
UInt32 seed;
- OSErr err = noErr;
- CFArrayRef pathesArray;
- LSSharedFileListRef list;
- LSSharedFileListItemRef itemRef;
- CFIndex i, pathesCount;
- CFURLRef cfURL = NULL;
- CFStringRef pathString = NULL;
- list = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteItems, NULL);
- pathesArray = LSSharedFileListCopySnapshot(list, &seed);
- pathesCount = CFArrayGetCount(pathesArray);
+ LSSharedFileListRef list = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteItems, NULL);
+ CFArrayRef pathesArray = LSSharedFileListCopySnapshot(list, &seed);
+ CFIndex pathesCount = CFArrayGetCount(pathesArray);
- for (i = 0; i < pathesCount; i++) {
- itemRef = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(pathesArray, i);
+ for (CFIndex i = 0; i < pathesCount; i++) {
+ LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(pathesArray, i);
- err = LSSharedFileListItemResolve(itemRef,
- kLSSharedFileListNoUserInteraction |
- kLSSharedFileListDoNotMountVolumes,
- &cfURL, NULL);
- if (err != noErr)
+ CFURLRef cfURL = NULL;
+ OSErr err = LSSharedFileListItemResolve(itemRef,
+ kLSSharedFileListNoUserInteraction |
+ kLSSharedFileListDoNotMountVolumes,
+ &cfURL, NULL);
+ if (err != noErr || !cfURL)
continue;
- pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
+ CFStringRef pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingUTF8))
continue;
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 374db92297d..287b98fa589 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -223,9 +223,10 @@ static void file_refresh(const bContext *C, ScrArea *sa)
filelist_setdir(sfile->files, params->dir);
filelist_setrecursion(sfile->files, params->recursion_level);
filelist_setsorting(sfile->files, params->sort);
- filelist_setfilter_options(sfile->files, (params->flag & FILE_HIDE_DOT) != 0,
+ filelist_setfilter_options(sfile->files, (params->flag & FILE_FILTER) != 0,
+ (params->flag & FILE_HIDE_DOT) != 0,
false, /* TODO hide_parent, should be controllable? */
- (params->flag & FILE_FILTER) ? params->filter : 0,
+ params->filter,
params->filter_id,
params->filter_glob,
params->filter_search);
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 516814b63b4..cbb8e98e7e0 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -616,30 +616,31 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
Object *ob2 = (Object *)dtar2->id;
PointerRNA dtar_ptr, dtar2_ptr;
uiLayout *col;
-
+
/* initialize RNA pointer to the target */
- RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
- RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
-
- /* Bone 1 */
+ RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
+ RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
+
+ /* Object 1 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Bone 1"), ICON_NONE);
-
+ uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object 1"), ICON_NONE);
+
if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
PointerRNA tar_ptr;
-
+
RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
-
+
+ /* Object 2 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Bone 2"), ICON_NONE);
-
+ uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Object 2"), ICON_NONE);
+
if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
PointerRNA tar_ptr;
-
+
RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
@@ -658,8 +659,8 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
/* initialize RNA pointer to the target */
RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
-
- /* Bone 1 */
+
+ /* Object 1 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object 1"), ICON_NONE);
@@ -673,7 +674,8 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
uiLayoutSetRedAlert(col, false); /* we can clear it again now - it's only needed when creating the ID/Bone fields */
uiItemR(col, &dtar_ptr, "transform_space", 0, NULL, ICON_NONE);
-
+
+ /* Object 2 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Object 2"), ICON_NONE);
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index f38d36853d7..861a38da2c7 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -195,8 +195,8 @@ static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
/* set the range directly */
get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL, false, false);
scene->r.flag |= SCER_PRV_RANGE;
- scene->r.psfra = iroundf(min);
- scene->r.pefra = iroundf(max);
+ scene->r.psfra = round_fl_to_int(min);
+ scene->r.pefra = round_fl_to_int(max);
/* set notifier that things have changed */
// XXX err... there's nothing for frame ranges yet, but this should do fine too
@@ -2036,7 +2036,7 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
}
else {
/* Animation Mode - Affects current frame (int) */
- CFRA = iroundf(ked.f1 / ked.i1);
+ CFRA = round_fl_to_int(ked.f1 / ked.i1);
SUBFRA = 0.f;
sipo->cursorVal = ked.f2 / (float)ked.i1;
}
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 75f0da83e77..5c670a216d8 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -94,7 +94,7 @@ static void graphview_cursor_apply(bContext *C, wmOperator *op)
* NOTE: sync this part of the code with ANIM_OT_change_frame
*/
/* 1) frame is rounded to the nearest int, since frames are ints */
- CFRA = iroundf(frame);
+ CFRA = round_fl_to_int(frame);
if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) {
/* Clip to preview range
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index b9d98dfe794..8037c2deb5b 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -428,7 +428,6 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *
RenderPass *rpass;
const char *fake_name;
int nr;
- int passflag = 0;
/* may have been freed since drawing */
rr = BKE_image_acquire_renderresult(scene, image);
@@ -450,30 +449,31 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *
fake_name = ui_imageuser_pass_fake_name(rl);
if (fake_name) {
- BLI_strncpy(rpass_fake.internal_name, fake_name, sizeof(rpass_fake.internal_name));
+ BLI_strncpy(rpass_fake.name, fake_name, sizeof(rpass_fake.name));
nr += 1;
}
+ ListBase added_passes;
+ BLI_listbase_clear(&added_passes);
+
/* rendered results don't have a Combined pass */
/* multiview: the ordering must be ascending, so the left-most pass is always the one picked */
for (rpass = rl ? rl->passes.first : NULL; rpass; rpass = rpass->next, nr++) {
-
/* just show one pass of each kind */
- if (passflag & rpass->passtype)
+ if (BLI_findstring_ptr(&added_passes, rpass->name, offsetof(LinkData, data))) {
continue;
+ }
+ BLI_addtail(&added_passes, BLI_genericNodeN(rpass->name));
- passflag |= rpass->passtype;
-
-final:
- uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->internal_name), 0, 0,
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->name), 0, 0,
UI_UNIT_X * 5, UI_UNIT_X, &iuser->pass, (float) nr, 0.0, 0, -1, "");
}
+ BLI_freelistN(&added_passes);
+
if (fake_name) {
- fake_name = NULL;
- rpass = &rpass_fake;
- nr = 0;
- goto final;
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass_fake.name), 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &iuser->pass, 0.0f, 0.0, 0, -1, "");
}
BKE_image_release_renderresult(scene, image);
@@ -633,7 +633,7 @@ static bool ui_imageuser_pass_menu_step(bContext *C, int direction, void *rnd_pt
int rp_index = iuser->pass + 1;
for (rp = rpass->next; rp; rp = rp->next, rp_index++) {
- if (rp->passtype != rpass->passtype) {
+ if (!STREQ(rp->name, rpass->name)) {
iuser->pass = rp_index;
changed = true;
break;
@@ -650,7 +650,7 @@ static bool ui_imageuser_pass_menu_step(bContext *C, int direction, void *rnd_pt
}
for (rp = rl->passes.first; rp; rp = rp->next, rp_index++) {
- if (rp->passtype == rpass->passtype) {
+ if (STREQ(rp->name, rpass->name)) {
iuser->pass = rp_index - 1;
changed = true;
break;
@@ -712,6 +712,10 @@ static void uiblock_layer_pass_buttons(
const char *display_name = "";
const bool show_stereo = (iuser->flag & IMA_SHOW_STEREO) != 0;
+ if (iuser->scene == NULL) {
+ return;
+ }
+
uiLayoutRow(layout, true);
/* layer menu is 1/3 larger than pass */
@@ -769,7 +773,7 @@ static void uiblock_layer_pass_buttons(
fake_name = ui_imageuser_pass_fake_name(rl);
rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL);
- display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : "");
+ display_name = rpass ? rpass->name : (fake_name ? fake_name : "");
rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
but = uiDefMenuBut(
block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name),
@@ -1204,7 +1208,7 @@ void uiTemplateImageStereo3d(uiLayout *layout, PointerRNA *stereo3d_format_ptr)
case S3D_DISPLAY_SIDEBYSIDE:
{
uiItemR(col, stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE);
- /* fall-through */
+ ATTR_FALLTHROUGH;
}
case S3D_DISPLAY_TOPBOTTOM:
{
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index e810f4db7dd..8cb23c9e021 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -88,7 +88,7 @@ static void draw_render_info(const bContext *C,
float zoomy)
{
RenderResult *rr;
- Render *re = RE_GetRender(scene->id.name);
+ Render *re = RE_GetSceneRender(scene);
RenderData *rd = RE_engine_get_render_data(re);
Scene *stats_scene = ED_render_job_get_scene(C);
if (stats_scene == NULL) {
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 6ca738b0e11..02e246d8630 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -52,6 +52,7 @@
#include "DNA_node_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
@@ -1066,6 +1067,7 @@ typedef struct ImageOpenData {
typedef struct ImageFrameRange {
struct ImageFrameRange *next, *prev;
ListBase frames;
+ /** The full path of the first file in the list of image files */
char filepath[FILE_MAX];
} ImageFrameRange;
@@ -1091,12 +1093,12 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
/**
* \brief Get a list of frames from the list of image files matching the first file name sequence pattern
* \param ptr [in] the RNA pointer containing the "directory" entry and "files" collection
- * \param frames [out] the list of frame numbers found in the files matching the first one by name
- * \param path [out] the full path of the first file in the list of image files
+ * \param frames_all [out] the list of frame numbers found in the files matching the first one by name
*/
static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all)
{
char dir[FILE_MAXDIR];
+ const bool do_frame_range = RNA_boolean_get(ptr, "use_sequence_detection");
ImageFrameRange *frame_range = NULL;
RNA_string_get(ptr, "directory", dir);
@@ -1112,7 +1114,8 @@ static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_al
frame->framenr = BLI_stringdec(filename, head, tail, &digits);
/* still in the same sequence */
- if ((frame_range != NULL) &&
+ if (do_frame_range &&
+ (frame_range != NULL) &&
(STREQLEN(base_head, head, FILE_MAX)) &&
(STREQLEN(base_tail, tail, FILE_MAX)))
{
@@ -1166,6 +1169,7 @@ static int image_sequence_get_len(ListBase *frames, int *ofs)
}
return frame_curr - (*ofs);
}
+ *ofs = 0;
return 0;
}
@@ -1218,7 +1222,7 @@ static Image *image_open_single(
static int image_open_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
+ ScrArea *sa = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
ImageUser *iuser = NULL;
@@ -1297,10 +1301,21 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (iod->iuser) {
iuser = iod->iuser;
}
- else if (sima) {
+ else if (sa->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = sa->spacedata.first;
ED_space_image_set(sima, scene, obedit, ima);
iuser = &sima->iuser;
}
+ else if (sa->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = sa->spacedata.first;
+
+ for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ if (bgpic->ima == ima) {
+ iuser = &bgpic->iuser;
+ break;
+ }
+ }
+ }
else {
Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
if (tex && tex->type == TEX_IMAGE) {
@@ -1313,7 +1328,12 @@ static int image_open_exec(bContext *C, wmOperator *op)
iuser->frames = frame_seq_len;
iuser->sfra = 1;
iuser->framenr = 1;
- iuser->offset = frame_ofs - 1;
+ if (ima->source == IMA_SRC_MOVIE) {
+ iuser->offset = 0;
+ }
+ else {
+ iuser->offset = frame_ofs - 1;
+ }
iuser->fie_ima = 2;
iuser->scene = scene;
BKE_image_init_imageuser(ima, iuser);
@@ -1436,6 +1456,9 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ RNA_def_boolean(ot->srna, "use_sequence_detection", true, "Detect Sequences",
+ "Automatically detect animated sequences in selected images (based on file names)");
}
/******************** Match movie length operator ********************/
@@ -1463,7 +1486,10 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
if (!ima || !iuser || !BKE_image_has_anim(ima))
return OPERATOR_CANCELLED;
- iuser->frames = IMB_anim_get_duration(((ImageAnim *) ima->anims.first)->anim, IMB_TC_RECORD_RUN);
+ struct anim *anim = ((ImageAnim *)ima->anims.first)->anim;
+ if (!anim)
+ return OPERATOR_CANCELLED;
+ iuser->frames = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN);
BKE_image_user_frame_calc(iuser, scene->r.cfra, 0);
return OPERATOR_FINISHED;
@@ -1875,7 +1901,6 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
}
else {
colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
- IMB_metadata_copy(colormanaged_ibuf, ibuf);
ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, imf, save_copy);
save_imbuf_post(ibuf, colormanaged_ibuf);
}
@@ -2361,8 +2386,8 @@ static int image_new_exec(bContext *C, wmOperator *op)
Main *bmain;
PointerRNA ptr, idptr;
PropertyRNA *prop;
- char _name[MAX_ID_NAME - 2];
- char *name = _name;
+ char name_buffer[MAX_ID_NAME - 2];
+ const char *name;
float color[4];
int width, height, floatbuf, gen_type, alpha;
int gen_context;
@@ -2375,10 +2400,13 @@ static int image_new_exec(bContext *C, wmOperator *op)
bmain = CTX_data_main(C);
prop = RNA_struct_find_property(op->ptr, "name");
- RNA_property_string_get(op->ptr, prop, name);
+ RNA_property_string_get(op->ptr, prop, name_buffer);
if (!RNA_property_is_set(op->ptr, prop)) {
/* Default value, we can translate! */
- name = (char *)DATA_(name);
+ name = DATA_(name_buffer);
+ }
+ else {
+ name = name_buffer;
}
width = RNA_int_get(op->ptr, "width");
height = RNA_int_get(op->ptr, "height");
@@ -2885,11 +2913,9 @@ static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
}
}
-/* Returns color in the display space, matching ED_space_node_color_sample(). */
-bool ED_space_image_color_sample(Scene *scene, SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
+/* Returns color in linear space, matching ED_space_node_color_sample(). */
+bool ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
{
- const char *display_device = scene->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
float fx, fy;
@@ -2923,10 +2949,6 @@ bool ED_space_image_color_sample(Scene *scene, SpaceImage *sima, ARegion *ar, in
}
}
- if (ret) {
- IMB_colormanagement_scene_linear_to_display_v3(r_col, display);
- }
-
ED_space_image_release_buffer(sima, ibuf, lock);
return ret;
}
@@ -3508,7 +3530,7 @@ static int frame_from_event(bContext *C, const wmEvent *event)
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
- framenr = iroundf(viewx);
+ framenr = round_fl_to_int(viewx);
}
return framenr;
@@ -3614,7 +3636,7 @@ static int render_border_exec(bContext *C, wmOperator *op)
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
- Render *re = RE_GetRender(scene->id.name);
+ Render *re = RE_GetSceneRender(scene);
RenderData *rd;
rctf border;
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 0e427623840..b87a0de23b9 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -162,7 +162,6 @@ static int pack_all_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
packAll(bmain, op->reports, true);
- G.fileflags |= G_AUTOPACK;
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c
index 074368a82c5..1559515221e 100644
--- a/source/blender/editors/space_logic/logic_ops.c
+++ b/source/blender/editors/space_logic/logic_ops.c
@@ -37,6 +37,7 @@
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 874e54ba5e7..3de44174d6a 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -47,8 +47,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
#include "BKE_action.h"
#include "BKE_context.h"
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 3243579f7d0..c774b99629c 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -502,51 +502,57 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
void nla_buttons_register(ARegionType *art)
{
PanelType *pt;
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animdata");
strcpy(pt->idname, "NLA_PT_animdata");
strcpy(pt->label, N_("Animation Data"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_animdata;
pt->poll = nla_animdata_panel_poll;
pt->flag = PNL_DEFAULT_CLOSED;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel track");
strcpy(pt->idname, "NLA_PT_track");
strcpy(pt->label, N_("Active Track"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_track;
pt->poll = nla_track_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_properties");
strcpy(pt->label, N_("Active Strip"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_properties;
pt->poll = nla_strip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_actionclip");
strcpy(pt->label, N_("Action Clip"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_actclip;
pt->poll = nla_strip_actclip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation");
strcpy(pt->idname, "NLA_PT_evaluation");
strcpy(pt->label, N_("Evaluation"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_evaluation;
pt->poll = nla_strip_eval_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers");
strcpy(pt->idname, "NLA_PT_modifiers");
strcpy(pt->label, N_("Modifiers"));
+ strcpy(pt->category, "Modifiers");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_modifiers;
pt->poll = nla_strip_eval_panel_poll;
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 5b3c062e16d..255fc0d6f8f 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -290,7 +290,8 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc)
* - min y-val is yminc, max is y-maxc, so clamp in those regions
*/
for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) {
- float y = evaluate_fcurve(fcu, cfra); // assume this to be in 0-1 range
+ float y = evaluate_fcurve(fcu, cfra);
+ CLAMP(y, 0.0f, 1.0f);
glVertex2f(cfra, ((y * yheight) + yminc));
}
glEnd(); // GL_LINE_STRIP
@@ -361,7 +362,7 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
glVertex2f(strip->start, yminc);
glEnd();
}
- /* fall-through */
+ ATTR_FALLTHROUGH;
/* this only draws after the strip */
case NLASTRIP_EXTEND_HOLD_FORWARD:
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 1f298373a80..f7f7c82171d 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -365,8 +365,8 @@ static int nlaedit_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
/* set the range directly */
get_nlastrip_extents(&ac, &min, &max, true);
scene->r.flag |= SCER_PRV_RANGE;
- scene->r.psfra = iroundf(min);
- scene->r.pefra = iroundf(max);
+ scene->r.psfra = round_fl_to_int(min);
+ scene->r.pefra = round_fl_to_int(max);
/* set notifier that things have changed */
// XXX err... there's nothing for frame ranges yet, but this should do fine too
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 7b08b8368ba..7ef34669ee2 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -638,7 +638,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
* highlight also if node itself is selected, since we don't display the node body separately!
*/
for (sock = node->inputs.first; sock; sock = sock->next) {
- node_socket_circle_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT));
+ node_socket_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT));
}
UI_block_end(C, node->block);
@@ -1234,6 +1234,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_BSDF_GLOSSY:
case SH_NODE_BSDF_GLASS:
case SH_NODE_BSDF_REFRACTION:
+ case SH_NODE_BSDF_PRINCIPLED:
ntype->draw_buttons = node_shader_buts_glossy;
break;
case SH_NODE_BSDF_ANISOTROPIC:
@@ -1320,9 +1321,6 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
PropertyRNA *prop;
const char *layer_name;
char scene_name[MAX_ID_NAME - 2];
- wmOperatorType *ot = WM_operatortype_find("RENDER_OT_render", 1);
-
- BLI_assert(ot != 0);
uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL);
@@ -1339,11 +1337,9 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
scn_ptr = RNA_pointer_get(ptr, "scene");
RNA_string_get(&scn_ptr, "name", scene_name);
- WM_operator_properties_create_ptr(&op_ptr, ot);
+ op_ptr = uiItemFullO(row, "RENDER_OT_render", "", ICON_RENDER_STILL, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&op_ptr, "layer", layer_name);
RNA_string_set(&op_ptr, "scene", scene_name);
- uiItemFullO_ptr(row, ot, "", ICON_RENDER_STILL, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
-
}
@@ -1629,17 +1625,6 @@ static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(col, ptr, "use_antialias_z", 0, NULL, ICON_NONE);
}
-
-static void node_composit_buts_hue_sat(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "color_hue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "color_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "color_value", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
-}
-
static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
@@ -1803,6 +1788,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
Scene *scene = CTX_data_scene(C);
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
PointerRNA active_input_ptr, op_ptr;
+ wmOperatorType *ot;
uiLayout *row, *col;
int active_index;
const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
@@ -1841,11 +1827,10 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
active_input_ptr.id.data = ptr->id.data;
col = uiLayoutColumn(row, true);
- op_ptr = uiItemFullO(col, "NODE_OT_output_file_move_active_socket", "",
- ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
+ op_ptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&op_ptr, "direction", 1);
- op_ptr = uiItemFullO(col, "NODE_OT_output_file_move_active_socket", "",
- ICON_TRIA_DOWN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ op_ptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&op_ptr, "direction", 2);
if (active_input_ptr.data) {
@@ -2177,14 +2162,7 @@ static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), Poi
static void node_composit_buts_switch_view_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
{
- PointerRNA op_ptr;
- wmOperatorType *ot = WM_operatortype_find("NODE_OT_switch_view_update", 1);
-
- BLI_assert(ot != 0);
-
- WM_operator_properties_create_ptr(&op_ptr, ot);
-
- uiItemFullO_ptr(layout, ot, "Update Views", ICON_FILE_REFRESH, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+ uiItemFullO(layout, "NODE_OT_switch_view_update", "Update Views", ICON_FILE_REFRESH, NULL, WM_OP_INVOKE_DEFAULT, 0);
}
static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2226,16 +2204,17 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo
if (node->custom1 == 0) {
const float backdropWidth = backdrop->x;
const float backdropHeight = backdrop->y;
- const float cx = x + snode->zoom * backdropWidth * node->custom3;
+ const float cx = x + snode->zoom * backdropWidth * node->custom3;
const float cy = y + snode->zoom * backdropHeight * node->custom4;
+ const float cross_size = 12 * U.pixelsize;
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINES);
- glVertex2f(cx - 25, cy - 25);
- glVertex2f(cx + 25, cy + 25);
- glVertex2f(cx + 25, cy - 25);
- glVertex2f(cx - 25, cy + 25);
+ glVertex2f(cx - cross_size, cy - cross_size);
+ glVertex2f(cx + cross_size, cy + cross_size);
+ glVertex2f(cx + cross_size, cy - cross_size);
+ glVertex2f(cx - cross_size, cy + cross_size);
glEnd();
}
}
@@ -2500,6 +2479,11 @@ static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
+static void node_composit_buts_brightcontrast(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE);
+}
+
/* only once called */
static void node_composit_set_butfunc(bNodeType *ntype)
{
@@ -2580,9 +2564,6 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_ALPHAOVER:
ntype->draw_buttons = node_composit_buts_alphaover;
break;
- case CMP_NODE_HUE_SAT:
- ntype->draw_buttons = node_composit_buts_hue_sat;
- break;
case CMP_NODE_TEXTURE:
ntype->draw_buttons = node_buts_texture;
break;
@@ -2730,6 +2711,8 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_SUNBEAMS:
ntype->draw_buttons = node_composit_buts_sunbeams;
break;
+ case CMP_NODE_BRIGHTCONTRAST:
+ ntype->draw_buttons = node_composit_buts_brightcontrast;
}
}
@@ -3101,7 +3084,7 @@ static void std_node_socket_draw(bContext *C, uiLayout *layout, PointerRNA *ptr,
node_file_output_socket_draw(C, layout, ptr, node_ptr);
return;
}
-
+
if ((sock->in_out == SOCK_OUT) || (sock->flag & SOCK_IN_USE) || (sock->flag & SOCK_HIDE_VALUE)) {
node_socket_button_label(C, layout, ptr, node_ptr, text);
return;
@@ -3450,7 +3433,6 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
/* store current linewidth */
float linew;
float arrow[2], arrow1[2], arrow2[2];
- const float px_fac = UI_DPI_WINDOW_FAC;
glGetFloatv(GL_LINE_WIDTH, &linew);
/* we can reuse the dist variable here to increment the GL curve eval amount*/
@@ -3477,7 +3459,7 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
}
if (do_triple) {
UI_ThemeColorShadeAlpha(th_col3, -80, -120);
- glLineWidth(4.0f * px_fac);
+ glLineWidth(4.0f);
glBegin(GL_LINE_STRIP);
for (i = 0; i <= LINK_RESOL; i++) {
@@ -3497,7 +3479,7 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
* for Intel hardware, this breaks with GL_LINE_STRIP and
* changing color in begin/end blocks.
*/
- glLineWidth(1.5f * px_fac);
+ glLineWidth(1.5f);
if (do_shaded) {
glBegin(GL_LINES);
for (i = 0; i < LINK_RESOL; i++) {
@@ -3632,7 +3614,7 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
return;
if (link->fromsock->flag & SOCK_UNAVAIL)
return;
-
+
if (link->flag & NODE_LINK_VALID) {
/* special indicated link, on drop-node */
if (link->flag & NODE_LINKFLAG_HILITE) {
@@ -3652,7 +3634,7 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
th_col1 = TH_REDALERT;
}
}
-
+
node_draw_link_bezier(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3);
// node_draw_link_straight(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3);
}
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index d49df2afbd4..dc6b06790e0 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -44,6 +44,8 @@
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_texture.h"
#include "ED_node.h" /* own include */
#include "ED_screen.h"
@@ -105,13 +107,15 @@ static bool add_reroute_intersect_check(bNodeLink *link, float mcoords[][2], int
if (node_link_bezier_points(NULL, NULL, link, coord_array, NODE_LINK_RESOL)) {
- for (i = 0; i < tot - 1; i++)
- for (b = 0; b < NODE_LINK_RESOL; b++)
+ for (i = 0; i < tot - 1; i++) {
+ for (b = 0; b < NODE_LINK_RESOL; b++) {
if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0) {
result[0] = (mcoords[i][0] + mcoords[i + 1][0]) / 2.0f;
result[1] = (mcoords[i][1] + mcoords[i + 1][1]) / 2.0f;
return 1;
}
+ }
+ }
}
return 0;
}
@@ -312,7 +316,10 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
switch (snode->nodetree->type) {
case NTREE_SHADER:
- type = SH_NODE_TEX_IMAGE;
+ if (BKE_scene_use_new_shading_nodes(CTX_data_scene(C)))
+ type = SH_NODE_TEX_IMAGE;
+ else
+ type = SH_NODE_TEXTURE;
break;
case NTREE_TEXTURE:
type = TEX_NODE_IMAGE;
@@ -333,7 +340,14 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- node->id = (ID *)ima;
+ if (type == SH_NODE_TEXTURE) {
+ Tex *tex = BKE_texture_add(CTX_data_main(C), DATA_(ima->id.name));
+ tex->ima = ima;
+ node->id = (ID *)tex;
+ WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, node->id);
+ }
+ else
+ node->id = (ID *)ima;
/* When adding new image file via drag-drop we need to load imbuf in order
* to get proper image source.
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index f0567924edd..925298451ce 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -133,6 +133,7 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa)
int in_out;
uiLayout *layout = pa->layout, *row, *split, *col;
PointerRNA ptr, sockptr, opptr;
+ wmOperatorType *ot;
if (!ntree)
return;
@@ -146,23 +147,25 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa)
split = uiLayoutRow(row, true);
col = uiLayoutColumn(split, true);
+ ot = WM_operatortype_find("NODE_OT_tree_socket_add", false);
uiItemL(col, IFACE_("Inputs:"), ICON_NONE);
uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "inputs", &ptr, "inputs", &ptr, "active_input",
NULL, 0, 0, 0, 0);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "in_out", SOCK_IN);
col = uiLayoutColumn(split, true);
uiItemL(col, IFACE_("Outputs:"), ICON_NONE);
uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "outputs", &ptr, "outputs", &ptr, "active_output",
NULL, 0, 0, 0, 0);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "in_out", SOCK_OUT);
+ ot = WM_operatortype_find("NODE_OT_tree_socket_move", false);
col = uiLayoutColumn(row, true);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_move", "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "direction", 1);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_move", "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "direction", 2);
if (sock) {
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index ab40c55b59d..d7119302611 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -617,34 +617,22 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
glDisable(GL_LINE_SMOOTH);
}
-/* this might have some more generic use */
-static void node_circle_draw(float x, float y, float size, const float col[4], int highlight)
+static void node_socket_shape_draw(
+ float x, float y, float size, const float col[4], bool highlight,
+ const float coords[][2], int coords_len)
{
- /* 16 values of sin function */
- static const float si[16] = {
- 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f,
- 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f,
- -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f,
- -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f
- };
- /* 16 values of cos function */
- static const float co[16] = {
- 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f,
- -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f,
- -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f,
- 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f,
- };
int a;
-
+
glColor4fv(col);
-
+
glEnable(GL_BLEND);
glBegin(GL_POLYGON);
- for (a = 0; a < 16; a++)
- glVertex2f(x + size * si[a], y + size * co[a]);
+ for (a = 0; a < coords_len; a++) {
+ glVertex2f(x + size * coords[a][0], y + size * coords[a][1]);
+ }
glEnd();
glDisable(GL_BLEND);
-
+
if (highlight) {
UI_ThemeColor(TH_TEXT_HI);
glLineWidth(1.5f);
@@ -655,14 +643,16 @@ static void node_circle_draw(float x, float y, float size, const float col[4], i
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glBegin(GL_LINE_LOOP);
- for (a = 0; a < 16; a++)
- glVertex2f(x + size * si[a], y + size * co[a]);
+ for (a = 0; a < coords_len; a++) {
+ glVertex2f(x + size * coords[a][0], y + size * coords[a][1]);
+ }
glEnd();
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
}
-void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, int highlight)
+
+void node_socket_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, bool highlight)
{
PointerRNA ptr, node_ptr;
float color[4];
@@ -670,7 +660,60 @@ void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, b
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color);
- node_circle_draw(sock->locx, sock->locy, size, color, highlight);
+
+ /* 16 values of {sin, cos} function */
+ const float shape_circle[16][2] = {
+ {0.00000000f, 1.00000000f},
+ {0.39435585f, 0.91895781f},
+ {0.72479278f, 0.68896691f},
+ {0.93775213f, 0.34730525f},
+ {0.99871650f, -0.05064916f},
+ {0.89780453f, -0.44039415f},
+ {0.65137248f, -0.75875812f},
+ {0.29936312f, -0.95413925f},
+ {-0.10116832f, -0.99486932f},
+ {-0.48530196f, -0.87434661f},
+ {-0.79077573f, -0.61210598f},
+ {-0.96807711f, -0.25065253f},
+ {-0.98846832f, 0.15142777f},
+ {-0.84864425f, 0.52896401f},
+ {-0.57126821f, 0.82076344f},
+ {-0.20129852f, 0.97952994f }
+ };
+
+ const float shape_diamond[4][2] = {
+ {0.0f, 1.2f},
+ {1.2f, 0.0f},
+ {0.0f, -1.2f},
+ {-1.2f, 0.0f},
+ };
+
+ const float shape_square[4][2] = {
+ {-0.9f, 0.9f},
+ {0.9f, 0.9f},
+ {0.9f, -0.9f},
+ {-0.9f, -0.9f},
+ };
+
+ const float (*shape)[2];
+ int shape_len;
+ switch (sock->draw_shape) {
+ default:
+ case SOCK_DRAW_SHAPE_CIRCLE:
+ shape = shape_circle;
+ shape_len = ARRAY_SIZE(shape_circle);
+ break;
+ case SOCK_DRAW_SHAPE_DIAMOND:
+ shape = shape_diamond;
+ shape_len = ARRAY_SIZE(shape_diamond);
+ break;
+ case SOCK_DRAW_SHAPE_SQUARE:
+ shape = shape_square;
+ shape_len = ARRAY_SIZE(shape_square);
+ break;
+ }
+
+ node_socket_shape_draw(sock->locx, sock->locy, size, color, highlight, shape, shape_len);
}
/* ************** Socket callbacks *********** */
@@ -820,14 +863,6 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
-#ifdef WITH_COMPOSITOR
- if (ntree->type == NTREE_COMPOSIT && (snode->flag & SNODE_SHOW_HIGHLIGHT)) {
- if (COM_isHighlightedbNode(node)) {
- UI_ThemeColorBlend(color_id, TH_ACTIVE, 0.5f);
- }
- }
-#endif
-
glLineWidth(1.0f);
UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
@@ -943,7 +978,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
if (nodeSocketIsHidden(sock))
continue;
- node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT);
+ node_socket_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT);
}
/* socket outputs */
@@ -951,7 +986,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
if (nodeSocketIsHidden(sock))
continue;
- node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT);
+ node_socket_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT);
}
/* preview */
@@ -989,16 +1024,6 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
if (node->flag & NODE_MUTED)
UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
-#ifdef WITH_COMPOSITOR
- if (ntree->type == NTREE_COMPOSIT && (snode->flag & SNODE_SHOW_HIGHLIGHT)) {
- if (COM_isHighlightedbNode(node)) {
- UI_ThemeColorBlend(color_id, TH_ACTIVE, 0.5f);
- }
- }
-#else
- (void)ntree;
-#endif
-
UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
/* outline active and selected emphasis */
@@ -1066,7 +1091,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
// BLI_snprintf(showname, sizeof(showname), "[%s]", showname); /* XXX - don't print into self! */
uiDefBut(node->block, UI_BTYPE_LABEL, 0, showname,
- iroundf(rct->xmin + NODE_MARGIN_X), iroundf(centy - NODE_DY * 0.5f),
+ round_fl_to_int(rct->xmin + NODE_MARGIN_X), round_fl_to_int(centy - NODE_DY * 0.5f),
(short)(BLI_rctf_size_x(rct) - 18.0f - 12.0f), (short)NODE_DY,
NULL, 0, 0, 0, 0, "");
}
@@ -1084,13 +1109,15 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
/* sockets */
for (sock = node->inputs.first; sock; sock = sock->next) {
- if (!nodeSocketIsHidden(sock))
- node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
+ if (!nodeSocketIsHidden(sock)) {
+ node_socket_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
+ }
}
for (sock = node->outputs.first; sock; sock = sock->next) {
- if (!nodeSocketIsHidden(sock))
- node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
+ if (!nodeSocketIsHidden(sock)) {
+ node_socket_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
+ }
}
UI_block_end(C, node->block);
@@ -1253,15 +1280,9 @@ static void snode_setup_v2d(SpaceNode *snode, ARegion *ar, const float center[2]
static void draw_nodetree(const bContext *C, ARegion *ar, bNodeTree *ntree, bNodeInstanceKey parent_key)
{
SpaceNode *snode = CTX_wm_space_node(C);
-
+
node_uiblocks_init(C, ntree);
-
-#ifdef WITH_COMPOSITOR
- if (ntree->type == NTREE_COMPOSIT) {
- COM_startReadHighlights();
- }
-#endif
-
+
node_update_nodetree(C, ntree);
node_draw_nodetree(C, ar, snode, ntree, parent_key);
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index ffe510016ff..e91fd1ee575 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -505,8 +505,6 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
ntreeUpdateTree(CTX_data_main(C), sce->nodetree);
-
- // XXX ntreeCompositForceHidden(sce->nodetree);
}
/* assumes nothing being done in ntree yet, sets the default in/out node */
@@ -582,17 +580,11 @@ void snode_set_context(const bContext *C)
}
}
- if (snode->nodetree != ntree || snode->id != id || snode->from != from) {
+ if (snode->nodetree != ntree || snode->id != id || snode->from != from ||
+ (snode->treepath.last == NULL && ntree))
+ {
ED_node_tree_start(snode, ntree, id, from);
}
-
- /* XXX Legacy hack to update render layer node outputs.
- * This should be handled by the depsgraph eventually ...
- */
- if (ED_node_is_compositor(snode) && snode->nodetree) {
- /* update output sockets based on available layers */
- ntreeCompositForceHidden(snode->nodetree);
- }
}
void snode_update(SpaceNode *snode, bNode *node)
@@ -1069,12 +1061,9 @@ int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **so
/* check if we click in a socket */
for (node = snode->edittree->nodes.first; node; node = node->next) {
-
- rect.xmin = cursor[0] - (NODE_SOCKSIZE + 4);
- rect.ymin = cursor[1] - (NODE_SOCKSIZE + 4);
- rect.xmax = cursor[0] + (NODE_SOCKSIZE + 4);
- rect.ymax = cursor[1] + (NODE_SOCKSIZE + 4);
-
+
+ BLI_rctf_init_pt_radius(&rect, cursor, NODE_SOCKSIZE + 4);
+
if (!(node->flag & NODE_HIDDEN)) {
/* extra padding inside and out - allow dragging on the text areas too */
if (in_out == SOCK_IN) {
@@ -1332,7 +1321,7 @@ static int node_read_fullsamplelayers_exec(bContext *C, wmOperator *UNUSED(op))
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
Scene *curscene = CTX_data_scene(C);
- Render *re = RE_NewRender(curscene->id.name);
+ Render *re = RE_NewSceneRender(curscene);
WM_cursor_wait(1);
RE_MergeFullSample(re, bmain, curscene, snode->nodetree);
@@ -2097,7 +2086,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
/* make sure all clipboard nodes would be valid in the target tree */
all_nodes_valid = true;
for (node = clipboard_nodes_lb->first; node; node = node->next) {
- if (!node->typeinfo->poll_instance(node, ntree)) {
+ if (!node->typeinfo->poll_instance || !node->typeinfo->poll_instance(node, ntree)) {
all_nodes_valid = false;
BKE_reportf(op->reports, RPT_ERROR, "Cannot add node %s into node tree %s", node->name, ntree->id.name + 2);
}
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 26eeaa91dd0..9d750bfe348 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -37,6 +37,7 @@
#include "DNA_anim_types.h"
#include "BLI_listbase.h"
+#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLT_translation.h"
@@ -92,9 +93,9 @@ static int node_group_operator_editable(bContext *C)
* Disabled otherwise to allow pynodes define their own operators
* with same keymap.
*/
- if (STREQ(snode->tree_idname, "ShaderNodeTree") ||
- STREQ(snode->tree_idname, "CompositorNodeTree") ||
- STREQ(snode->tree_idname, "TextureNodeTree"))
+ if (ED_node_is_shader(snode) ||
+ ED_node_is_compositor(snode) ||
+ ED_node_is_texture(snode))
{
return true;
}
@@ -112,11 +113,11 @@ static const char *group_node_idname(bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
- if (STREQ(snode->tree_idname, "ShaderNodeTree"))
+ if (ED_node_is_shader(snode))
return "ShaderNodeGroup";
- else if (STREQ(snode->tree_idname, "CompositorNodeTree"))
+ else if (ED_node_is_compositor(snode))
return "CompositorNodeGroup";
- else if (STREQ(snode->tree_idname, "TextureNodeTree"))
+ else if (ED_node_is_texture(snode))
return "TextureNodeGroup";
return "";
@@ -186,6 +187,7 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode)
bNode *node, *nextnode;
bNodeTree *ngroup, *wgroup;
ListBase anim_basepaths = {NULL, NULL};
+ LinkNode *nodes_delayed_free = NULL;
ngroup = (bNodeTree *)gnode->id;
@@ -208,8 +210,8 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode)
* This also removes remaining links to and from interface nodes.
*/
if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
- nodeFreeNode(wgroup, node);
- continue;
+ /* We must delay removal since sockets will reference this node. see: T52092 */
+ BLI_linklist_prepend(&nodes_delayed_free, node);
}
/* keep track of this node's RNA "base" path (the part of the path identifying the node)
@@ -336,6 +338,11 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode)
}
}
+ while (nodes_delayed_free) {
+ node = BLI_linklist_pop(&nodes_delayed_free);
+ nodeFreeNode(ntree, node);
+ }
+
/* delete the group instance */
nodeFreeNode(ntree, gnode);
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 6b8fa0b88fe..352f9e51012 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -67,8 +67,9 @@ void snode_group_offset(struct SpaceNode *snode, float *x, float *y); /* transfo
/* node_draw.c */
int node_get_colorid(struct bNode *node);
-void node_socket_circle_draw(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node,
- struct bNodeSocket *sock, float size, int highlight);
+void node_socket_draw(
+ const struct bContext *C, struct bNodeTree *ntree, struct bNode *node,
+ struct bNodeSocket *sock, float size, bool highlight);
int node_get_resize_cursor(int directions);
void node_draw_shadow(struct SpaceNode *snode, struct bNode *node, float radius, float alpha);
void node_draw_default(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode,
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index 5f592431558..3b03399a5e7 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -567,7 +567,13 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
ntree->is_updating = true;
for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
bNodeLink *link = linkdata->data;
-
+
+ /* See note below, but basically TEST flag means that the link
+ * was connected to output (or to a node which affects the
+ * output).
+ */
+ do_tag_update |= (link->flag & NODE_LINK_TEST) != 0;
+
if (apply_links && link->tosock && link->fromsock) {
/* before actually adding the link,
* let nodes perform special link insertion handling
@@ -593,11 +599,6 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
}
}
else {
- /* See note below, but basically TEST flag means that the link
- * was connected to output (or to a node which affects the
- * output).
- */
- do_tag_update |= (link->flag & NODE_LINK_TEST) != 0;
nodeRemLink(ntree, link);
}
}
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index ec525e684b0..5d0877a1eff 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -683,10 +683,11 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree,
RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
/* indented label */
- for (i = 0; i < indent; i++)
+ for (i = 0; i < indent; i++) {
label[i] = ' ';
+ }
label[indent] = '\0';
- BLI_snprintf(label, UI_MAX_NAME_STR, "%s%s:", label, IFACE_(input->name));
+ BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s:", IFACE_(input->name));
/* split in label and value */
split = uiLayoutSplit(layout, 0.35f, false);
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 8c5d2d82468..f497a06cb12 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -345,7 +345,7 @@ static int backimage_fit_exec(bContext *C, wmOperator *UNUSED(op))
ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
- if (ibuf == NULL) {
+ if ((ibuf == NULL) || (ibuf->x == 0) || (ibuf->y == 0)) {
BKE_image_release_ibuf(ima, ibuf, lock);
return OPERATOR_CANCELLED;
}
@@ -417,20 +417,18 @@ static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
}
}
-/* Returns color in the display space, matching ED_space_image_color_sample().
+/* Returns color in linear space, matching ED_space_image_color_sample().
* And here we've got recursion in the comments tips...
*/
-bool ED_space_node_color_sample(Scene *scene, SpaceNode *snode, ARegion *ar, int mval[2], float r_col[3])
+bool ED_space_node_color_sample(SpaceNode *snode, ARegion *ar, int mval[2], float r_col[3])
{
- const char *display_device = scene->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
void *lock;
Image *ima;
ImBuf *ibuf;
float fx, fy, bufx, bufy;
bool ret = false;
- if (STREQ(snode->tree_idname, ntreeType_Composite->idname) || (snode->flag & SNODE_BACKDRAW) == 0) {
+ if (!ED_node_is_compositor(snode) || (snode->flag & SNODE_BACKDRAW) == 0) {
/* use viewer image for color sampling only if we're in compositor tree
* with backdrop enabled
*/
@@ -471,10 +469,6 @@ bool ED_space_node_color_sample(Scene *scene, SpaceNode *snode, ARegion *ar, int
}
}
- if (ret) {
- IMB_colormanagement_scene_linear_to_display_v3(r_col, display);
- }
-
BKE_image_release_ibuf(ima, ibuf, lock);
return ret;
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index bbdf6feef01..2267316d257 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -753,6 +753,10 @@ static void node_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegi
break;
}
break;
+ case NC_WM:
+ if (wmn->data == ND_JOB)
+ ED_region_tag_redraw(ar);
+ break;
case NC_SCENE:
case NC_MATERIAL:
case NC_TEXTURE:
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 33a5a7ca7b7..af6fdf2ab86 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -40,6 +40,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_mempool.h"
@@ -1039,9 +1040,6 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
struct DrawIconArg arg;
float aspect;
- /* icons tiny bit away from text */
- x -= 0.15f * UI_UNIT_Y;
-
/* make function calls a bit compacter */
arg.block = block;
arg.id = tselem->id;
@@ -1052,8 +1050,10 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
/* placement of icons, copied from interface_widgets.c */
aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
- arg.x = x = x + 4.0f * aspect;
- arg.y = y = y + 0.1f * UI_UNIT_Y;
+ x += 2.0f * aspect;
+ y += 2.0f * aspect;
+ arg.x = x;
+ arg.y = y;
if (tselem->type) {
switch (tselem->type) {
@@ -1125,6 +1125,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
case eModifierType_Cast:
UI_icon_draw(x, y, ICON_MOD_CAST); break;
case eModifierType_MeshDeform:
+ case eModifierType_SurfaceDeform:
UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break;
case eModifierType_Bevel:
UI_icon_draw(x, y, ICON_MOD_BEVEL); break;
@@ -1272,7 +1273,10 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
}
}
else {
- switch (GS(tselem->id->name)) {
+ /* TODO(sergey): Casting to short here just to handle ID_NLA which is
+ * NOT inside of IDType enum.
+ */
+ switch ((short)GS(tselem->id->name)) {
case ID_SCE:
tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break;
case ID_ME:
@@ -1342,6 +1346,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break;
case ID_GD:
tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break;
+ default:
+ break;
}
}
}
@@ -1387,9 +1393,9 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa
UI_draw_roundbox_corner_set(UI_CNR_ALL);
glColor4ub(255, 255, 255, 100);
UI_draw_roundbox(
- (float) *offsx - 1.0f * ufac,
+ (float) *offsx + 1.0f * ufac,
(float)ys + 1.0f * ufac,
- (float)*offsx + UI_UNIT_X - 2.0f * ufac,
+ (float)*offsx + UI_UNIT_X - 1.0f * ufac,
(float)ys + UI_UNIT_Y - ufac,
(float)UI_UNIT_Y / 2.0f - ufac);
glEnable(GL_BLEND); /* roundbox disables */
@@ -1534,9 +1540,9 @@ static void outliner_draw_tree_element(
if (active != OL_DRAWSEL_NONE) {
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox(
- (float)startx + UI_UNIT_X,
+ (float)startx + UI_UNIT_X + 1.0f * ufac,
(float)*starty + 1.0f * ufac,
- (float)startx + 2.0f * UI_UNIT_X - 2.0f * ufac,
+ (float)startx + 2.0f * UI_UNIT_X - 1.0f * ufac,
(float)*starty + UI_UNIT_Y - 1.0f * ufac,
UI_UNIT_Y / 2.0f - 1.0f * ufac);
glEnable(GL_BLEND); /* roundbox disables it */
@@ -1547,16 +1553,13 @@ static void outliner_draw_tree_element(
/* open/close icon, only when sublevels, except for scene */
if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) {
int icon_x;
- if (tselem->type == 0 && ELEM(te->idcode, ID_OB, ID_SCE))
- icon_x = startx;
- else
- icon_x = startx + 5 * ufac;
+ icon_x = startx;
// icons a bit higher
if (TSELEM_OPEN(tselem, soops))
- UI_icon_draw((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_DOWN);
+ UI_icon_draw((float)icon_x + 2 * ufac, (float)*starty + 1 * ufac, ICON_DISCLOSURE_TRI_DOWN);
else
- UI_icon_draw((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_RIGHT);
+ UI_icon_draw((float)icon_x + 2 * ufac, (float)*starty + 1 * ufac, ICON_DISCLOSURE_TRI_RIGHT);
}
offsx += UI_UNIT_X;
@@ -1566,7 +1569,7 @@ static void outliner_draw_tree_element(
tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, 1.0f);
- offsx += UI_UNIT_X;
+ offsx += UI_UNIT_X + 2 * ufac;
}
else
offsx += 2 * ufac;
@@ -1574,16 +1577,16 @@ static void outliner_draw_tree_element(
if (tselem->type == 0 && ID_IS_LINKED_DATABLOCK(tselem->id)) {
glPixelTransferf(GL_ALPHA_SCALE, 0.5f);
if (tselem->id->tag & LIB_TAG_MISSING) {
- UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN);
+ UI_icon_draw((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN);
}
else if (tselem->id->tag & LIB_TAG_INDIRECT) {
- UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT);
+ UI_icon_draw((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT);
}
else {
- UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT);
+ UI_icon_draw((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT);
}
glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
- offsx += UI_UNIT_X;
+ offsx += UI_UNIT_X + 2 * ufac;
}
glDisable(GL_BLEND);
@@ -1755,7 +1758,7 @@ static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegio
// gray hierarchy lines
UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.4f);
starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET;
- startx = 6;
+ startx = UI_UNIT_X / 2 - 1.0f;
outliner_draw_hierarchy(soops, &soops->tree, startx, &starty);
// items themselves
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 345ac353c11..f4089667b04 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -309,9 +309,12 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
ID *id = tselem->id;
BLI_assert(te->idcode != 0 && id != NULL);
- BLI_assert(te->idcode != ID_LI || ((Library *)id)->parent == NULL);
UNUSED_VARS_NDEBUG(te);
+ if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked library '%s'", id->name);
+ return;
+ }
if (id->tag & LIB_TAG_INDIRECT) {
BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name);
return;
@@ -516,7 +519,8 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
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, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
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);
@@ -1088,7 +1092,7 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
te = outliner_find_id(so, &so->tree, &obact->id);
- if (obact->type == OB_ARMATURE) {
+ if (te != NULL && obact->type == OB_ARMATURE) {
/* traverse down the bone hierarchy in case of armature */
TreeElement *te_obact = te;
@@ -1940,7 +1944,7 @@ static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEv
{
/* present a prompt to informing users that this change is irreversible */
return WM_operator_confirm_message(C, op,
- "Purging unused data-blocks cannot be undone. "
+ "Purging unused data-blocks cannot be undone and saves to current .blend file. "
"Click here to proceed...");
}
@@ -1962,7 +1966,8 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
/* identifiers */
ot->idname = "OUTLINER_OT_orphans_purge";
ot->name = "Purge All";
- ot->description = "Clear all orphaned data-blocks without any users from the file (cannot be undone)";
+ ot->description = "Clear all orphaned data-blocks without any users from the file "
+ "(cannot be undone, saves to current .blend file)";
/* callbacks */
ot->invoke = outliner_orphans_purge_invoke;
@@ -2068,74 +2073,62 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false);
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
-
PointerRNA ptr;
- WM_operator_properties_create_ptr(&ptr, ot);
+ /* Cannot use uiItemEnumO()... have multiple properties to set. */
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_OBJECT);
- /* Cannot use uiItemEnumO()... have multiple properties to set. */
- uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
+
/* par becomes parent, make the associated menus */
if (par->type == OB_ARMATURE) {
- WM_operator_properties_create_ptr(&ptr, ot);
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE);
- uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME);
- uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE);
- uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO);
- uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_BONE);
- uiItemFullO_ptr(layout, ot, IFACE_("Bone"),
- 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
}
else if (par->type == OB_CURVE) {
- WM_operator_properties_create_ptr(&ptr, ot);
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_CURVE);
- uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_FOLLOW);
- uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_PATH_CONST);
- uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
}
else if (par->type == OB_LATTICE) {
- WM_operator_properties_create_ptr(&ptr, ot);
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_LATTICE);
- uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
}
UI_popup_menu_end(C, pup);
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 89df471990a..18cc2a015e6 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -470,10 +470,11 @@ static eOLDrawState tree_element_active_defgroup(
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
}
else {
- if (ob == OBACT)
+ if (ob == OBACT) {
if (ob->actdef == te->index + 1) {
return OL_DRAWSEL_NORMAL;
}
+ }
}
return OL_DRAWSEL_NONE;
}
@@ -706,7 +707,12 @@ static eOLDrawState tree_element_active_pose(
{
Object *ob = (Object *)tselem->id;
Base *base = BKE_scene_base_find(scene, ob);
-
+
+ if (base == NULL) {
+ /* Armature not instantiated in current scene (e.g. inside an appended group...). */
+ return OL_DRAWSEL_NONE;
+ }
+
if (set != OL_SETSEL_NONE) {
if (scene->obedit)
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 13200e92e7e..29dcf73109c 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -235,8 +235,7 @@ static void unlink_group_cb(
}
else {
Main *bmain = CTX_data_main(C);
- BKE_libblock_unlink(bmain, group, false, false);
- BKE_libblock_free(bmain, group);
+ BKE_libblock_delete(bmain, group);
}
}
@@ -399,7 +398,7 @@ static void object_deselect_cb(
static void object_delete_cb(
bContext *C, ReportList *reports, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *user_data)
{
Base *base = (Base *)te->directdata;
@@ -411,7 +410,9 @@ static void object_delete_cb(
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) {
+ else if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
+ ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0)
+ {
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);
@@ -429,6 +430,13 @@ static void object_delete_cb(
tselem->id = NULL;
#endif
}
+ else {
+ /* No base, means object is no more instantiated in any scene.
+ * Should not happen ideally, but does happens, see T51625.
+ * Rather than twisting in all kind of ways to address all possible cases leading to that situation, simpler
+ * to allow deleting such object as a mere generic data-block. */
+ id_delete_cb(C, reports, scene, te, tsep, tselem, user_data);
+ }
}
static void id_local_cb(
@@ -442,6 +450,9 @@ static void id_local_cb(
if (id_make_local(bmain, tselem->id, false, false) == false) {
id_clear_lib_data(bmain, tselem->id);
}
+ else {
+ BKE_main_id_clear_newpoins(bmain);
+ }
}
}
@@ -522,7 +533,7 @@ static void group_linkobs2scene_cb(
if (!base) {
/* link to scene */
base = BKE_scene_base_add(scene, gob->ob);
- id_lib_extern((ID *)gob->ob); /* in case these are from a linked group */
+ id_us_plus(&gob->ob->id);
}
base->object->flag |= SELECT;
base->flag |= SELECT;
@@ -839,7 +850,9 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s
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) {
+ else if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
+ ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0)
+ {
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);
@@ -1044,7 +1057,7 @@ 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_DELETE, "DELETE", 0, "Delete Group", ""},
{OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users",
"Make all users of selected data-blocks to use instead current (clicked) one"},
{OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""},
@@ -1083,7 +1096,7 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
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);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
break;
case OL_GROUPOP_REMAP:
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
@@ -1247,6 +1260,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
{
if (idlevel > 0) {
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
+ ED_undo_push(C, "Delete");
}
break;
}
@@ -1254,6 +1268,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
{
if (idlevel > 0) {
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
+ ED_undo_push(C, "Remap");
}
break;
}
@@ -1362,18 +1377,20 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
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");
+ ED_undo_push(C, "Rename Library");
break;
}
case OL_LIB_DELETE:
{
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
+ ED_undo_push(C, "Delete Library");
break;
}
case OL_LIB_RELOCATE:
{
/* rename */
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL);
+ ED_undo_push(C, "Relocate Library");
break;
}
case OL_LIB_RELOAD:
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 20f7ca4db16..41125478ec0 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -882,6 +882,8 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
}
break;
}
+ default:
+ break;
}
}
@@ -1080,6 +1082,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv;
PropertyRNA *prop, *iterprop;
PropertyType proptype;
+
+ /* Don't display arrays larger, weak but index is stored as a short,
+ * also the outliner isn't intended for editing such large data-sets. */
+ BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!");
+ const int tot_limit = SHRT_MAX;
+
int a, tot;
/* we do lazy build, for speed and to avoid infinite recusion */
@@ -1101,6 +1109,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
iterprop = RNA_struct_iterator_property(ptr->type);
tot = RNA_property_collection_length(ptr, iterprop);
+ CLAMP_MAX(tot, tot_limit);
/* auto open these cases */
if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER)
@@ -1147,6 +1156,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
}
else if (proptype == PROP_COLLECTION) {
tot = RNA_property_collection_length(ptr, prop);
+ CLAMP_MAX(tot, tot_limit);
if (TSELEM_OPEN(tselem, soops)) {
for (a = 0; a < tot; a++) {
@@ -1159,6 +1169,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
}
else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
tot = RNA_property_array_length(ptr, prop);
+ CLAMP_MAX(tot, tot_limit);
if (TSELEM_OPEN(tselem, soops)) {
for (a = 0; a < tot; a++)
@@ -1316,7 +1327,7 @@ static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeE
ten = outliner_add_element(soops, &te->subtree, lbarray[a], NULL, TSE_ID_BASE, 0);
ten->directdata = lbarray[a];
- ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name));
+ ten->name = BKE_idcode_to_name_plural(GS(id->name));
if (ten->name == NULL)
ten->name = "UNKNOWN";
@@ -1356,7 +1367,7 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0);
ten->directdata = lbarray[a];
- ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name));
+ ten->name = BKE_idcode_to_name_plural(GS(id->name));
if (ten->name == NULL)
ten->name = "UNKNOWN";
@@ -1645,11 +1656,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
outliner_free_tree(&soops->tree);
outliner_storage_cleanup(soops);
- /* clear ob id.new flags */
- for (Object *ob = mainvar->object.first; ob; ob = ob->id.next) {
- ob->id.newid = NULL;
- }
-
/* options */
if (soops->outlinevis == SO_LIBRARIES) {
Library *lib;
@@ -1835,6 +1841,8 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
outliner_sort(&soops->tree);
}
outliner_filter_tree(soops, &soops->tree);
+
+ BKE_main_id_clear_newpoins(mainvar);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index ede6b7ce469..46f212e3679 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -38,6 +38,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
@@ -445,6 +447,7 @@ void SEQUENCER_OT_movieclip_strip_add(struct wmOperatorType *ot)
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
prop = RNA_def_enum(ot->srna, "clip", DummyRNA_NULL_items, 0, "Clip", "");
RNA_def_enum_funcs(prop, RNA_movieclip_itemf);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_MOVIECLIP);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
ot->prop = prop;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index e1768e4aedc..97961501c6d 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -40,6 +40,7 @@
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
+#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
@@ -545,7 +546,8 @@ static void draw_seq_text(View2D *v2d, SpaceSeq *sseq, Sequence *seq, float x1,
if ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM)) {
str[0] = 0;
str_len = 0;
- } else if (seq->sound) {
+ }
+ else if (seq->sound) {
str_len = BLI_snprintf(str, sizeof(str), "%s: %s | %d",
name, seq->sound->name, seq->len);
}
@@ -1115,18 +1117,16 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
bool draw_metadata = false;
- if (G.is_rendering == false && (scene->r.seq_flag & R_SEQ_GL_PREV) == 0) {
+ if (G.is_rendering == false && (scene->r.seq_prev_type) == OB_RENDER) {
/* stop all running jobs, except screen one. currently previews frustrate Render
* needed to make so sequencer's rendering doesn't conflict with compositor
*/
WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_COMPOSITE);
- if ((scene->r.seq_flag & R_SEQ_GL_PREV) == 0) {
- /* in case of final rendering used for preview, kill all previews,
- * otherwise threading conflict will happen in rendering module
- */
- WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_RENDER_PREVIEW);
- }
+ /* in case of final rendering used for preview, kill all previews,
+ * otherwise threading conflict will happen in rendering module
+ */
+ WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_RENDER_PREVIEW);
}
if ((!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) && !draw_backdrop) {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 8ae89941bdb..196527dcc60 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -562,7 +562,7 @@ int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequen
}
if (seq1 == NULL) seq1 = seq2;
if (seq3 == NULL) seq3 = seq2;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case 2:
if (seq1 == NULL || seq2 == NULL) {
*error_str = N_("2 selected sequence strips are needed");
@@ -727,7 +727,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
if (!skip_dup) {
/* Duplicate AFTER the first change */
- seqn = BKE_sequence_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
+ seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
}
if (seqn) {
@@ -820,7 +820,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
if (!skip_dup) {
/* Duplicate AFTER the first change */
- seqn = BKE_sequence_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
+ seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
}
if (seqn) {
@@ -1232,7 +1232,7 @@ static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
void SEQUENCER_OT_snap(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Snap Strips";
+ ot->name = "Snap Strips to Frame";
ot->idname = "SEQUENCER_OT_snap";
ot->description = "Frame where selected strips will be snapped";
@@ -2162,7 +2162,7 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
if (ed == NULL)
return OPERATOR_CANCELLED;
- BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT);
+ BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT, 0);
if (nseqbase.first) {
Sequence *seq = nseqbase.first;
@@ -3200,7 +3200,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME);
+ BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME, 0);
/* To make sure the copied strips have unique names between each other add
* them temporarily to the end of the original seqbase. (bug 25932)
@@ -3267,7 +3267,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
ED_sequencer_deselect_all(scene);
ofs = scene->r.cfra - seqbase_clipboard_frame;
- BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME);
+ BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME, 0);
/* transform pasted strips before adding */
if (ofs) {
@@ -3352,6 +3352,9 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
if (seq_act->sound) BKE_sound_add_scene_sound_defaults(scene, seq_act);
if (seq_other->sound) BKE_sound_add_scene_sound_defaults(scene, seq_other);
+ BKE_sequence_invalidate_cache(scene, seq_act);
+ BKE_sequence_invalidate_cache(scene, seq_other);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -3509,7 +3512,7 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50");
bool proxy_75 = RNA_boolean_get(op->ptr, "proxy_75");
bool proxy_100 = RNA_boolean_get(op->ptr, "proxy_100");
- bool override = RNA_boolean_get(op->ptr, "override");
+ bool overwrite = RNA_boolean_get(op->ptr, "overwrite");
bool turnon = true;
if (ed == NULL || !(proxy_25 || proxy_50 || proxy_75 || proxy_100)) {
@@ -3545,7 +3548,7 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
else
seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_100;
- if (!override)
+ if (!overwrite)
seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
else
seq->strip->proxy->build_flags &= ~SEQ_PROXY_SKIP_EXISTING;
@@ -3577,7 +3580,7 @@ void SEQUENCER_OT_enable_proxies(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "proxy_50", false, "50%", "");
RNA_def_boolean(ot->srna, "proxy_75", false, "75%", "");
RNA_def_boolean(ot->srna, "proxy_100", false, "100%", "");
- RNA_def_boolean(ot->srna, "override", false, "Override", "");
+ RNA_def_boolean(ot->srna, "overwrite", false, "Overwrite", "");
}
/* change ops */
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 48c49f36471..d88ed36e392 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -683,7 +683,7 @@ static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
if (!select_more_less_seq__internal(scene, false, false))
return OPERATOR_CANCELLED;
-
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index a2a80297041..f1d0f23f8af 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -435,6 +435,7 @@ static void sequencer_dropboxes(void)
/* ************* end drop *********** */
+/* DO NOT make this static, this hides the symbol and breaks API generation script. */
const char *sequencer_context_dir[] = {"edit_mask", NULL};
static int sequencer_context(const bContext *C, const char *member, bContextDataResult *result)
diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt
index de85ddc40ab..39b48f5b52c 100644
--- a/source/blender/editors/space_text/CMakeLists.txt
+++ b/source/blender/editors/space_text/CMakeLists.txt
@@ -43,6 +43,8 @@ set(SRC
text_format.c
text_format_lua.c
text_format_osl.c
+ text_format_pov.c
+ text_format_pov_ini.c
text_format_py.c
text_header.c
text_ops.c
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 686a10fc785..fcb46ced750 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -158,7 +158,7 @@ static void text_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
}
ED_area_tag_redraw(sa);
- /* fall-through */ /* fall down to tag redraw */
+ ATTR_FALLTHROUGH; /* fall down to tag redraw */
case NA_ADDED:
case NA_REMOVED:
ED_area_tag_redraw(sa);
@@ -636,5 +636,7 @@ void ED_spacetype_text(void)
ED_text_format_register_py();
ED_text_format_register_osl();
ED_text_format_register_lua();
+ ED_text_format_register_pov();
+ ED_text_format_register_pov_ini();
}
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index c38c57b9528..da5fa9da046 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -328,7 +328,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
if (tools & TOOL_SUGG_LIST) {
texttool_suggest_clear();
}
- if (tools & TOOL_DOCUMENT) {
+ if (tools & TOOL_DOCUMENT) {
texttool_docs_clear();
doc_scroll = 0;
}
@@ -455,7 +455,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
break;
case PAGEDOWNKEY:
scroll = SUGG_LIST_SIZE - 1;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case WHEELDOWNMOUSE:
case DOWNARROWKEY:
if (event->val == KM_PRESS) {
@@ -489,7 +489,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
break;
case PAGEUPKEY:
scroll = SUGG_LIST_SIZE - 1;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case WHEELUPMOUSE:
case UPARROWKEY:
if (event->val == KM_PRESS) {
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 81605a80f69..70b5feac280 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -926,6 +926,7 @@ static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back)
/*********************** draw documentation *******************************/
+#if 0
static void draw_documentation(const SpaceText *st, ARegion *ar)
{
TextDrawContext tdc = {0};
@@ -1014,6 +1015,7 @@ static void draw_documentation(const SpaceText *st, ARegion *ar)
draw_documentation(st, ar);
}
}
+#endif
/*********************** draw suggestion list *******************************/
@@ -1487,7 +1489,7 @@ void draw_text_main(SpaceText *st, ARegion *ar)
/* draw other stuff */
draw_brackets(st, &tdc, ar);
draw_textscroll(st, &scroll, &back);
- draw_documentation(st, ar);
+ /* draw_documentation(st, ar); - No longer supported */
draw_suggestion_list(st, &tdc, ar);
text_font_end(&tdc);
diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h
index b901ec83a9c..d7cf31d0b41 100644
--- a/source/blender/editors/space_text/text_format.h
+++ b/source/blender/editors/space_text/text_format.h
@@ -102,6 +102,8 @@ void ED_text_format_register(TextFormatType *tft);
void ED_text_format_register_py(void);
void ED_text_format_register_osl(void);
void ED_text_format_register_lua(void);
+void ED_text_format_register_pov(void);
+void ED_text_format_register_pov_ini(void);
#define STR_LITERAL_STARTSWITH(str, str_literal, len_var) \
(strncmp(str, str_literal, len_var = (sizeof(str_literal) - 1)) == 0)
diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c
new file mode 100644
index 00000000000..1ef3322711c
--- /dev/null
+++ b/source/blender/editors/space_text/text_format_pov.c
@@ -0,0 +1,903 @@
+/*
+ * ***** 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
+ * 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/space_text/text_format_pov.c
+ * \ingroup sptext
+ */
+
+#include <string.h>
+
+#include "BLI_blenlib.h"
+
+#include "DNA_text_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_text.h"
+
+#include "text_format.h"
+
+/* *** POV Keywords (for format_line) *** */
+
+/* Checks the specified source string for a POV keyword (minus boolean & 'nil').
+ * This name must start at the beginning of the source string and must be
+ * followed by a non-identifier (see text_check_identifier(char)) or null char.
+ *
+ * If a keyword is found, the length of the matching word is returned.
+ * Otherwise, -1 is returned.
+ *
+ * See:
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+
+static int txtfmt_pov_find_keyword(const char *string)
+{
+ int i, len;
+ /* Language Directives */
+ if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "persistent", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "declare", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "default", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "elseif", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "error", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fclose", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fopen", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ifndef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ifdef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "patch", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "local", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "macro", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "range", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "read", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "render", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "switch", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "undef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "write", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len;
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+static int txtfmt_pov_find_reserved_keywords(const char *string)
+{
+ int i, len;
+ /* POV-Ray Built-in Variables
+ * list is from...
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+
+ /* Float Functions */
+ if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_intersections", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "dimension_size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bitwise_and", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bitwise_or", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bitwise_xor", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "file_exists", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "precompute", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "dimensions", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clipped_by", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "shadowless", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "turb_depth", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "reciprocal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quaternion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "phong_size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tesselate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "save_file", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "load_file", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_trace", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "transform", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "translate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "direction", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "roughness", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "metallic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gts_load", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gts_save", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "location", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "altitude", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "function", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "evaluate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "inverse", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "collect", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "target", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "albedo", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rotate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "matrix", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "look_at", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "jitter", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "angle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "right", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "scale", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "child", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "crand", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "blink", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "defined", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "degrees", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "inside", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "radians", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vlength", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "select", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "floor", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "strcmp", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "strlen", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tessel", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sturm", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "abs", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "acosh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "prod", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "with", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "acos", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "asc", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "asinh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "asin", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "atan2", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "atand", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "atanh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "atan", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ceil", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "warp", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cosh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "log", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "min", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mod", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pow", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rand", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "seed", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "form", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sinh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sqrt", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tanh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vdot", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sin", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sqr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sum", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pwr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tan", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "val", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cos", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "div", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "exp", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "int", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sky", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "up", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ln", len)) i = len;
+ /* Color Identifiers */
+ else if (STR_LITERAL_STARTSWITH(string, "transmit", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "filter", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "srgbft", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "srgbf", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "srgbt", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rgbft", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gamma", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "green", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "blue", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gray", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "srgb", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sRGB", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SRGB", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rgbf", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rgbt", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rgb", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "red", len)) i = len;
+ /* Color Spaces */
+ else if (STR_LITERAL_STARTSWITH(string, "pov", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hsl", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hsv", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "xyl", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "xyv", len)) i = len;
+ /* Vector Functions */
+ else if (STR_LITERAL_STARTSWITH(string, "vaxis_rotate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vturbulence", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "min_extent", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vnormalize", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vrotate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vcross", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "trace", len)) i = len;
+ /* String Functions */
+ else if (STR_LITERAL_STARTSWITH(string, "file_time", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "datetime", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "concat", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "strlwr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "strupr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "substr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vstr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "chr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "str", len)) i = len;
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+
+static int txtfmt_pov_find_reserved_builtins(const char *string)
+{
+ int i, len;
+
+ /* POV-Ray Built-in Variables
+ * list is from...
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+ /* Language Keywords */
+ if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "area_illumination", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "all_intersections", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cutaway_textures", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "smooth_triangle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "lommel_seeliger", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "falloff_angle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "aa_threshold", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hypercomplex", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "major_radius", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_distance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_iteration", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "colour_space", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "color_space", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "iridescence", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "subsurface", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "scattering", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "absorption", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "water_level", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "reflection", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "oren_nayar", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "refraction", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hierarchy", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "radiosity", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tolerance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "interior", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "toroidal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "emission", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "material", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "internal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "photons", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "arc_angle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "minnaert", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "texture", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "array", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "black_hole", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "component", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "composite", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "coords", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cube", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "dist_exp", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "exterior", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "file_gamma", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "flatness", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "planet", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "screw", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "keep", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "flip", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "move", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "roll", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "look_at", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "metric", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "offset", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "orientation", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pattern", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "precision", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "repeat", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bend", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "alpha", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "slice", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "smooth", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "solid", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "all", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "now", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pot", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "type", len)) i = len;
+ /* Animation Options */
+ else if (STR_LITERAL_STARTSWITH(string, "global_settings", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "input_file_name", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "initial_clock", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "initial_frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_height", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len;
+ /* Spline Identifiers */
+ else if (STR_LITERAL_STARTSWITH(string, "extended_x_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "general_x_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quadratic_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "basic_x_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "natural_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "linear_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bezier_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "akima_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sor_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tcb_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "linear_sweep", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "conic_sweep", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "b_spline", len)) i = len;
+ /* Patterns */
+ else if (STR_LITERAL_STARTSWITH(string, "pigment_pattern", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_pattern", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "density_file", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cylindrical", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "proportion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "triangular", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "proximity", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spherical", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bump_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "wrinkles", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "average", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "voronoi", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "masonry", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "binary", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "boxed", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bozo", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "brick", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bumps", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cells", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "checker", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "crackle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "dents", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "facets", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gradient", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "granite", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hexagon", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "julia", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "leopard", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "magnet", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mandel", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "marble", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "onion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pavement", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "planar", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quilted", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "radial", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ripples", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "slope", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spiral1", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spiral2", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spotted", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "square", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tile2", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tiling", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tiles", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "waves", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "wood", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "agate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "aoi", len)) i = len;
+ /* Objects */
+ else if (STR_LITERAL_STARTSWITH(string, "superellipsoid", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bicubic_patch", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "julia_fractal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "height_field", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sphere_sweep", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "light_group", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "light_source", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "intersection", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "isosurface", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "background", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sky_sphere", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cylinder", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "difference", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "brilliance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "parametric", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "interunion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "intermerge", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "polynomial", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "displace", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "specular", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ambient", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "diffuse", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "polygon", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quadric", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quartic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rainbow", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sphere", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "prism", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "camera", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "galley", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "phong", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cone", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "blob", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "box", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "disc", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fog", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "lathe", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "merge", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mesh2", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mesh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "object", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ovus", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "lemon", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "plane", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "poly", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "irid", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sor", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "text", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "torus", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "triangle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "union", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "colour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "color", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "media", len)) i = len;
+ /* Built-in Vectors */
+ else if (STR_LITERAL_STARTSWITH(string, "t", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "u", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "v", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "x", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "y", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "z", len)) i = len;
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+
+/* Checks the specified source string for a POV modifiers. This
+ * name must start at the beginning of the source string and must be followed
+ * by a non-identifier (see text_check_identifier(char)) or null character.
+ *
+ * If a special name is found, the length of the matching name is returned.
+ * Otherwise, -1 is returned.
+ *
+ * See:
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+
+static int txtfmt_pov_find_specialvar(const char *string)
+{
+ int i, len;
+ /* Modifiers */
+ if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "projected_through", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "double_illuminate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "expand_thresholds", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "media_interaction", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "media_attenuation", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "low_error_factor", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "recursion_limit", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "interior_texture", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_trace_level", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gray_threshold", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pretrace_start", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "normal_indices", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "normal_vectors", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vertex_vectors", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "noise_generator", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "irid_wavelength", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "number_of_waves", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ambient_light", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "inside_vector", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "face_indices", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "texture_list", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_gradient", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uv_indices", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uv_vectors", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fade_distance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "global_lights", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no_bump_scale", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pretrace_end", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no_radiosity", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no_reflection", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "assumed_gamma", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "scallop_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "triangle_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "nearest_count", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "maximum_reuse", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "minimum_reuse", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "always_sample", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "translucency", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "eccentricity", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "contained_by", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "inside_point", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "adc_bailout", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "density_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "split_union", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mm_per_unit", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "agate_turb", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bounded_by", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "brick_size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hf_gray_16", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "dispersion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "extinction", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "thickness", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "color_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "colour_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fade_colour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fade_power", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fade_color", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "normal_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pigment_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quick_color", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quick_colour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "material_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pass_through", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "interpolate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "texture_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "error_bound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "brightness", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "use_color", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "use_alpha", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "use_colour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "use_index", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uv_mapping", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "importance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_sample", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "intervals", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sine_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "slope_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "poly_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no_shadow", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ramp_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "precision", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "original", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "accuracy", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "map_type", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no_image", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "distance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "autostop", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "caustics", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "octaves", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "aa_level", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "frequency", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fog_offset", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "modulation", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "outbound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no_cache", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pigment", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "charset", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "inbound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "outside", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "inner", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "turbulence", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "threshold", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "accuracy", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "polarity", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bump_size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "circular", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "control0", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "control1", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "maximal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "minimal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fog_type", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fog_alt", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "samples", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "origin", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "amount", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "adaptive", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "exponent", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "strength", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "density", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fresnel", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "albinos", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "finish", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "method", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "omega", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fixed", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spacing", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "u_steps", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "v_steps", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "offset", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hollow", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gather", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "lambda", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mortar", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "count", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "once", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "orient", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "normal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "phase", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ratio", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "open", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ior", len)) i = len;
+ /* Light Types and options*/
+ else if (STR_LITERAL_STARTSWITH(string, "area_light", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "looks_like", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fade_power", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tightness", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spotlight", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "parallel", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "point_at", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "falloff", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "radius", len)) i = len;
+ /* Camera Types and options*/
+ else if (STR_LITERAL_STARTSWITH(string, "omni_directional_stereo", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "lambert_cylindrical", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "miller_cylindrical", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "lambert_azimuthal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ultra_wide_angle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "camera_direction", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "camera_location ", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "van_der_grinten", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "aitoff_hammer", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "smyth_craster", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "orthographic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "camera_right", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "blur_samples", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "plate_carree", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "camera_type", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "perspective", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mesh_camera", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "focal_point", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "balthasart", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "confidence", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "parallaxe", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hobo_dyer", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "camera_up", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "panoramic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "eckert_vi", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "eckert_iv", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mollweide", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "aperture", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "behrmann", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "variance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "stereo", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "icosa", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tetra", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "octa", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mercator", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "omnimax", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fisheye", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "edwards", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "peters", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gall", len)) i = len;
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+static int txtfmt_pov_find_bool(const char *string)
+{
+ int i, len;
+ /*Built-in Constants*/
+ if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "false", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "off", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "true", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "yes", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "on", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pi", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tau", len)) i = len;
+ /* Encodings */
+ else if (STR_LITERAL_STARTSWITH(string, "sint16be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint16le", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint32be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint32le", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint16be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint16le", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bt2020", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bt709", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint8", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint8", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ascii", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "utf8", len)) i = len;
+ /* Filetypes */
+ else if (STR_LITERAL_STARTSWITH(string, "tiff", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "df3", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "exr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gif", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hdr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "iff", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "jpeg", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pgm", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "png", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ppm", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sys", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tga", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ttf", len)) i = len;
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+static char txtfmt_pov_format_identifier(const char *str)
+{
+ char fmt;
+ if ((txtfmt_pov_find_specialvar(str)) != -1) fmt = FMT_TYPE_SPECIAL;
+ else if ((txtfmt_pov_find_keyword(str)) != -1) fmt = FMT_TYPE_KEYWORD;
+ else if ((txtfmt_pov_find_reserved_keywords(str)) != -1) fmt = FMT_TYPE_RESERVED;
+ else if ((txtfmt_pov_find_reserved_builtins(str)) != -1) fmt = FMT_TYPE_DIRECTIVE;
+ else fmt = FMT_TYPE_DEFAULT;
+ return fmt;
+}
+
+static void txtfmt_pov_format_line(SpaceText *st, TextLine *line, const bool do_next)
+{
+ FlattenString fs;
+ const char *str;
+ char *fmt;
+ char cont_orig, cont, find, prev = ' ';
+ int len, i;
+
+ /* Get continuation from previous line */
+ if (line->prev && line->prev->format != NULL) {
+ fmt = line->prev->format;
+ cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+ BLI_assert((FMT_CONT_ALL & cont) == cont);
+ }
+ else {
+ cont = FMT_CONT_NOP;
+ }
+
+ /* Get original continuation from this line */
+ if (line->format != NULL) {
+ fmt = line->format;
+ cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+ BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig);
+ }
+ else {
+ cont_orig = 0xFF;
+ }
+
+ len = flatten_string(st, &fs, line->line);
+ str = fs.buf;
+ if (!text_check_format_len(line, len)) {
+ flatten_string_free(&fs);
+ return;
+ }
+ fmt = line->format;
+
+ while (*str) {
+ /* Handle escape sequences by skipping both \ and next char */
+ if (*str == '\\') {
+ *fmt = prev; fmt++; str++;
+ if (*str == '\0') break;
+ *fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str);
+ continue;
+ }
+ /* Handle continuations */
+ else if (cont) {
+ /* C-Style comments */
+ if (cont & FMT_CONT_COMMENT_C) {
+ if (*str == '*' && *(str + 1) == '/') {
+ *fmt = FMT_TYPE_COMMENT; fmt++; str++;
+ *fmt = FMT_TYPE_COMMENT;
+ cont = FMT_CONT_NOP;
+ }
+ else {
+ *fmt = FMT_TYPE_COMMENT;
+ }
+ /* Handle other comments */
+ }
+ else {
+ find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\'';
+ if (*str == find) cont = 0;
+ *fmt = FMT_TYPE_STRING;
+ }
+
+ str += BLI_str_utf8_size_safe(str) - 1;
+ }
+ /* Not in a string... */
+ else {
+ /* C-Style (multi-line) comments */
+ if (*str == '/' && *(str + 1) == '*') {
+ cont = FMT_CONT_COMMENT_C;
+ *fmt = FMT_TYPE_COMMENT; fmt++; str++;
+ *fmt = FMT_TYPE_COMMENT;
+ }
+ /* Single line comment */
+ else if (*str == '/' && *(str + 1) == '/') {
+ text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format));
+ }
+ else if (*str == '"' || *str == '\'') {
+ /* Strings */
+ find = *str;
+ cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
+ *fmt = FMT_TYPE_STRING;
+ }
+ /* Whitespace (all ws. has been converted to spaces) */
+ else if (*str == ' ') {
+ *fmt = FMT_TYPE_WHITESPACE;
+ }
+ /* Numbers (digits not part of an identifier and periods followed by digits) */
+ else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) ||
+ (*str == '.' && text_check_digit(*(str + 1))))
+ {
+ *fmt = FMT_TYPE_NUMERAL;
+ }
+ /* Booleans */
+ else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_pov_find_bool(str)) != -1) {
+ if (i > 0) {
+ text_format_fill_ascii(&str, &fmt, FMT_TYPE_NUMERAL, i);
+ }
+ else {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ }
+ /* Punctuation */
+ else if (text_check_delim(*str)) {
+ *fmt = FMT_TYPE_SYMBOL;
+ }
+ /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ else if (prev == FMT_TYPE_DEFAULT) {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ else {
+ /* Special vars(v) or built-in keywords(b) */
+ /* keep in sync with 'txtfmt_pov_format_identifier()' */
+ if ((i = txtfmt_pov_find_specialvar(str)) != -1) prev = FMT_TYPE_SPECIAL;
+ else if ((i = txtfmt_pov_find_keyword(str)) != -1) prev = FMT_TYPE_KEYWORD;
+ else if ((i = txtfmt_pov_find_reserved_keywords(str)) != -1) prev = FMT_TYPE_RESERVED;
+ else if ((i = txtfmt_pov_find_reserved_builtins(str)) != -1) prev = FMT_TYPE_DIRECTIVE;
+
+ if (i > 0) {
+ text_format_fill_ascii(&str, &fmt, prev, i);
+ }
+ else {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ }
+ }
+ prev = *fmt; fmt++; str++;
+ }
+
+ /* Terminate and add continuation char */
+ *fmt = '\0'; fmt++;
+ *fmt = cont;
+
+ /* If continuation has changed and we're allowed, process the next line */
+ if (cont != cont_orig && do_next && line->next) {
+ txtfmt_pov_format_line(st, line->next, do_next);
+ }
+
+ flatten_string_free(&fs);
+}
+
+void ED_text_format_register_pov(void)
+{
+ static TextFormatType tft = {NULL};
+ static const char *ext[] = {"pov", "inc", "mcr", "mac", NULL};
+
+ tft.format_identifier = txtfmt_pov_format_identifier;
+ tft.format_line = txtfmt_pov_format_line;
+ tft.ext = ext;
+
+ ED_text_format_register(&tft);
+}
diff --git a/source/blender/editors/space_text/text_format_pov_ini.c b/source/blender/editors/space_text/text_format_pov_ini.c
new file mode 100644
index 00000000000..453dd1d748c
--- /dev/null
+++ b/source/blender/editors/space_text/text_format_pov_ini.c
@@ -0,0 +1,491 @@
+/*
+ * ***** 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
+ * 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/space_text/text_format_pov_ini.c
+ * \ingroup sptext
+ */
+
+#include <string.h>
+
+#include "BLI_blenlib.h"
+
+#include "DNA_text_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_text.h"
+
+#include "text_format.h"
+
+/* *** POV INI Keywords (for format_line) *** */
+
+/* Checks the specified source string for a POV INI keyword (minus boolean & 'nil').
+ * This name must start at the beginning of the source string and must be
+ * followed by a non-identifier (see text_check_identifier(char)) or null char.
+ *
+ * If a keyword is found, the length of the matching word is returned.
+ * Otherwise, -1 is returned.
+ *
+ * See:
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+
+static int txtfmt_ini_find_keyword(const char *string)
+{
+ int i, len;
+ /* Language Directives */
+ if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "declare", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "default", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fclose", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ifndef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "elseif", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "error", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fopen", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ifdef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "local", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "macro", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "range", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "render", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "switch", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "undef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "write", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "read", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len;
+
+ else if (STR_LITERAL_STARTSWITH(string, "I", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "S", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "A", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Q", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "U", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "F", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "C", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "N", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "P", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "T", len)) i = len;
+
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+static int txtfmt_ini_find_reserved(const char *string)
+{
+ int i, len;
+ /* POV-Ray Built-in INI Variables
+ * list is from...
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+ if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Create_Continue_Trace_Log", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSoundEnabled", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSoundEnabled", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "HideWhenMainMinimized", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Antialias_Confidence", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "UseExtensions", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ReadWriteSourceDir", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionLeft", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionTop", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionRight", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionBottom", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionX", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionY", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Antialias_Threshold", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Antialias_Gamma", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Antialias_Depth", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "input_file_name", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Subset_Start_Frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Subset_End_Frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "UseToolbar", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "UseTooltips", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Frame_Step", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Cyclic_Animation", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Field_Render", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Odd_Field", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "initial_clock", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "initial_frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_height", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Start_Column", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Start_Row", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "End_Column", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "End_Row", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Test_Abort_Count", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Test_Abort", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Continue_Trace", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Bounding_Method", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Create_Ini", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Display_Gamma", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Display", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Version", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Pause_When_Done", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Verbose", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Preview_Start_Size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Preview_End_Size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Output_to_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Input_File_Name", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Output_File_Name", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Output_File_Type", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Output_Alpha", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Bits_Per_Color", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Compression", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Dither_Method", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Include_Header", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Library_Path", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Debug_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Fatal_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Render_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Statistic_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Warning_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Warning_Level", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "All_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Debug_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Fatal_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Render_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Statistic_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Warning_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "All_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Quality", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Bounding_Threshold", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Bounding", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Light_Buffer", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Vista_Buffer", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Remove_Bounds", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Split_Unions", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Antialias", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Glare_Desaturation", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Sampling_Method", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Stochastic_Seed", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Jitter_Amount", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Jitter", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Antialias_Depth", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "CheckNewVersion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "RunCount", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "CommandLine", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "TextColour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "WarningColour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ErrorColour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "BackgroundColour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "DropToEditor", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastRenderName", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastRenderPath", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastQueuePath", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SecondaryINISection", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "BetaVersionNo64", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastBitmapName", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastBitmapPath", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastINIPath", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SecondaryINIFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "BackgroundFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SaveSettingsOnExit", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "TileBackground", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "HideNewUserHelp", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SendSystemInfo", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ItsAboutTime", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastPath", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Band0Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Band1Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Band2Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Band3Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Band4Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ShowCmd", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Transparency", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Use8BitMode", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "MakeActive", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "KeepAboveMain", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "AutoClose", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "PreserveBitmap", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "FontSize", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "FontWeight", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "KeepMessages", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "AlertSound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Completion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Priority", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "DutyCycle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "AlertOnCompletion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "AutoRender", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "PreventSleep", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NoShelloutWait", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SystemNoActive", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NoShellOuts", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "VideoSource", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SceneFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "OutputFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "IniOutputFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "CurrentDirectory", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SourceFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Rendering", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "RenderwinClose", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Append_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Warning Level", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Height", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Dither", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Flags", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Font", len)) i = len;
+ /* Filetypes */
+ else if (STR_LITERAL_STARTSWITH(string, "df3", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "exr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gif", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hdr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "iff", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "jpeg", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pgm", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "png", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ppm", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sys", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tga", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tiff", len)) i = len;
+ /* Encodings */
+ else if (STR_LITERAL_STARTSWITH(string, "ascii", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "utf8", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint8", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint16be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint16le", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint8", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint16be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint16le", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint32be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint32le", len)) i = len;
+
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+
+
+
+static int txtfmt_ini_find_bool(const char *string)
+{
+ int i, len;
+ /* Built-in Constants */
+ if (STR_LITERAL_STARTSWITH(string, "false", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "off", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "true", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "yes", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "on", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pi", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tau", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%o", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%s", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%n", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%k", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%h", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%w", len)) i = len;
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+static char txtfmt_pov_ini_format_identifier(const char *str)
+{
+ char fmt;
+ if ((txtfmt_ini_find_keyword(str)) != -1) fmt = FMT_TYPE_KEYWORD;
+ else if ((txtfmt_ini_find_reserved(str)) != -1) fmt = FMT_TYPE_RESERVED;
+ else fmt = FMT_TYPE_DEFAULT;
+ return fmt;
+}
+
+static void txtfmt_pov_ini_format_line(SpaceText *st, TextLine *line, const bool do_next)
+{
+ FlattenString fs;
+ const char *str;
+ char *fmt;
+ char cont_orig, cont, find, prev = ' ';
+ int len, i;
+
+ /* Get continuation from previous line */
+ if (line->prev && line->prev->format != NULL) {
+ fmt = line->prev->format;
+ cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+ BLI_assert((FMT_CONT_ALL & cont) == cont);
+ }
+ else {
+ cont = FMT_CONT_NOP;
+ }
+
+ /* Get original continuation from this line */
+ if (line->format != NULL) {
+ fmt = line->format;
+ cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+ BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig);
+ }
+ else {
+ cont_orig = 0xFF;
+ }
+
+ len = flatten_string(st, &fs, line->line);
+ str = fs.buf;
+ if (!text_check_format_len(line, len)) {
+ flatten_string_free(&fs);
+ return;
+ }
+ fmt = line->format;
+
+ while (*str) {
+ /* Handle escape sequences by skipping both \ and next char */
+ if (*str == '\\') {
+ *fmt = prev; fmt++; str++;
+ if (*str == '\0') break;
+ *fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str);
+ continue;
+ }
+ /* Handle continuations */
+ else if (cont) {
+ /* Multi-line comments */
+ if (cont & FMT_CONT_COMMENT_C) {
+ if (*str == ']' && *(str + 1) == ']') {
+ *fmt = FMT_TYPE_COMMENT; fmt++; str++;
+ *fmt = FMT_TYPE_COMMENT;
+ cont = FMT_CONT_NOP;
+ }
+ else {
+ *fmt = FMT_TYPE_COMMENT;
+ }
+ /* Handle other comments */
+ }
+ else {
+ find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\'';
+ if (*str == find) cont = 0;
+ *fmt = FMT_TYPE_STRING;
+ }
+
+ str += BLI_str_utf8_size_safe(str) - 1;
+ }
+ /* Not in a string... */
+ else {
+ /* Multi-line comments not supported */
+ /* Single line comment */
+ if (*str == ';') {
+ text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format));
+ }
+ else if (*str == '"' || *str == '\'') {
+ /* Strings */
+ find = *str;
+ cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
+ *fmt = FMT_TYPE_STRING;
+ }
+ /* Whitespace (all ws. has been converted to spaces) */
+ else if (*str == ' ') {
+ *fmt = FMT_TYPE_WHITESPACE;
+ }
+ /* Numbers (digits not part of an identifier and periods followed by digits) */
+ else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) ||
+ (*str == '.' && text_check_digit(*(str + 1))))
+ {
+ *fmt = FMT_TYPE_NUMERAL;
+ }
+ /* Booleans */
+ else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_ini_find_bool(str)) != -1) {
+ if (i > 0) {
+ text_format_fill_ascii(&str, &fmt, FMT_TYPE_NUMERAL, i);
+ }
+ else {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ }
+ /* Punctuation */
+ else if ((*str != '#') && text_check_delim(*str)) {
+ *fmt = FMT_TYPE_SYMBOL;
+ }
+ /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ else if (prev == FMT_TYPE_DEFAULT) {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ else {
+ /* Special vars(v) or built-in keywords(b) */
+ /* keep in sync with 'txtfmt_ini_format_identifier()' */
+ if ((i = txtfmt_ini_find_keyword(str)) != -1) prev = FMT_TYPE_KEYWORD;
+ else if ((i = txtfmt_ini_find_reserved(str)) != -1) prev = FMT_TYPE_RESERVED;
+
+ if (i > 0) {
+ text_format_fill_ascii(&str, &fmt, prev, i);
+ }
+ else {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ }
+ }
+ prev = *fmt; fmt++; str++;
+ }
+
+ /* Terminate and add continuation char */
+ *fmt = '\0'; fmt++;
+ *fmt = cont;
+
+ /* If continuation has changed and we're allowed, process the next line */
+ if (cont != cont_orig && do_next && line->next) {
+ txtfmt_pov_ini_format_line(st, line->next, do_next);
+ }
+
+ flatten_string_free(&fs);
+}
+
+void ED_text_format_register_pov_ini(void)
+{
+ static TextFormatType tft = {NULL};
+ static const char *ext[] = {"ini", NULL};
+
+ tft.format_identifier = txtfmt_pov_ini_format_identifier;
+ tft.format_line = txtfmt_pov_ini_format_line;
+ tft.ext = ext;
+
+ ED_text_format_register(&tft);
+}
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 83012eac39e..f603fa1b0f1 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -248,12 +248,14 @@ static int text_open_exec(bContext *C, wmOperator *op)
pprop = op->customdata;
if (pprop->prop) {
+ id_us_ensure_real(&text->id);
RNA_id_pointer_create(&text->id, &idptr);
RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
RNA_property_update(C, &pprop->ptr, pprop->prop);
}
else if (st) {
st->text = text;
+ id_us_ensure_real(&text->id);
st->left = 0;
st->top = 0;
st->scroll_accum[0] = 0.0f;
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index 15eb154c757..f29d2b30ffe 100644
--- a/source/blender/editors/space_time/space_time.c
+++ b/source/blender/editors/space_time/space_time.c
@@ -329,6 +329,8 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
case ID_CF:
cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL);
break;
+ default:
+ break;
}
/* build linked-list for searching */
diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
index cf738de0202..f0e65f84205 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -75,6 +75,80 @@ void draw_motion_paths_init(View3D *v3d, ARegion *ar)
glLoadMatrixf(rv3d->viewmat);
}
+/* set color
+* - more intense for active/selected bones, less intense for unselected bones
+* - black for before current frame, green for current frame, blue for after current frame
+* - intensity decreases as distance from current frame increases
+*
+* If the user select custom color, the color is replaced for the color selected in UI panel
+* - 75% Darker color is used for previous frames
+* - 50% Darker color for current frame
+* - User selected color for next frames
+*/
+static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra,
+ float prev_color[3], float frame_color[3], float next_color[3])
+{
+ int frame = sfra + i;
+ int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */
+
+#define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min)
+ float intensity; /* how faint */
+
+ if (frame < CFRA) {
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ /* Custom color: previous frames color is darker than current frame */
+ glColor3fv(prev_color);
+ }
+ else {
+ /* black - before cfra */
+ if (sel) {
+ /* intensity = 0.5f; */
+ intensity = SET_INTENSITY(sfra, i, CFRA, 0.25f, 0.75f);
+ }
+ else {
+ /* intensity = 0.8f; */
+ intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f);
+ }
+ UI_ThemeColorBlend(TH_WIRE, blend_base, intensity);
+ }
+ }
+ else if (frame > CFRA) {
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ /* Custom color: next frames color is equal to user selected color */
+ glColor3fv(next_color);
+ }
+ else {
+ /* blue - after cfra */
+ if (sel) {
+ /* intensity = 0.5f; */
+ intensity = SET_INTENSITY(CFRA, i, efra, 0.25f, 0.75f);
+ }
+ else {
+ /* intensity = 0.8f; */
+ intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f);
+ }
+ UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity);
+ }
+ }
+ else {
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ /* Custom color: current frame color is slightly darker than user selected color */
+ glColor3fv(frame_color);
+ }
+ else {
+ /* green - on cfra */
+ if (sel) {
+ intensity = 0.5f;
+ }
+ else {
+ intensity = 0.99f;
+ }
+ UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10);
+ }
+ }
+#undef SET_INTENSITY
+}
+
/* Draw the given motion path for an Object or a Bone
* - assumes that the viewport has already been initialized properly
* i.e. draw_motion_paths_init() has been called
@@ -86,6 +160,28 @@ void draw_motion_path_instance(Scene *scene,
bMotionPathVert *mpv, *mpv_start;
int i, stepsize = avs->path_step;
int sfra, efra, sind, len;
+ float prev_color[3];
+ float frame_color[3];
+ float next_color[3];
+
+ /* Custom color - Previous frames: color is darker than current frame */
+ prev_color[0] = mpath->color[0] * 0.25f;
+ prev_color[1] = mpath->color[1] * 0.25f;
+ prev_color[2] = mpath->color[2] * 0.25f;
+
+ /* Custom color - Current frame: color is slightly darker than user selected color */
+ frame_color[0] = mpath->color[0] * 0.50f;
+ frame_color[1] = mpath->color[1] * 0.50f;
+ frame_color[2] = mpath->color[2] * 0.50f;
+
+ /* Custom color - Next frames: color is equal to user selection */
+ next_color[0] = mpath->color[0];
+ next_color[1] = mpath->color[1];
+ next_color[2] = mpath->color[2];
+
+ /* Save old line width */
+ GLfloat old_width;
+ glGetFloatv(GL_LINE_WIDTH, &old_width);
/* get frame ranges */
if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
@@ -130,64 +226,27 @@ void draw_motion_path_instance(Scene *scene,
mpv_start = (mpath->points + sind);
/* draw curve-line of path */
-
- glBegin(GL_LINE_STRIP);
- for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
- short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT);
- float intensity; /* how faint */
-
- int frame = sfra + i;
- int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */
-
- /* set color
- * - more intense for active/selected bones, less intense for unselected bones
- * - black for before current frame, green for current frame, blue for after current frame
- * - intensity decreases as distance from current frame increases
- */
-#define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min)
- if (frame < CFRA) {
- /* black - before cfra */
- if (sel) {
- /* intensity = 0.5f; */
- intensity = SET_INTENSITY(sfra, i, CFRA, 0.25f, 0.75f);
- }
- else {
- /* intensity = 0.8f; */
- intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f);
- }
- UI_ThemeColorBlend(TH_WIRE, blend_base, intensity);
- }
- else if (frame > CFRA) {
- /* blue - after cfra */
- if (sel) {
- /* intensity = 0.5f; */
- intensity = SET_INTENSITY(CFRA, i, efra, 0.25f, 0.75f);
- }
- else {
- /* intensity = 0.8f; */
- intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f);
- }
- UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity);
- }
- else {
- /* green - on cfra */
- if (sel) {
- intensity = 0.5f;
- }
- else {
- intensity = 0.99f;
- }
- UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10);
+ /* Draw lines only if line drawing option is enabled */
+ if (mpath->flag & MOTIONPATH_FLAG_LINES) {
+ /* set line thickness */
+ glLineWidth(mpath->line_thickness);
+
+ glBegin(GL_LINE_STRIP);
+ for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
+ short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT);
+ /* Set color */
+ set_motion_path_color(scene, mpath, i, sel, sfra, efra, prev_color, frame_color, next_color);
+ /* draw a vertex with this color */
+ glVertex3fv(mpv->co);
}
-#undef SET_INTENSITY
- /* draw a vertex with this color */
- glVertex3fv(mpv->co);
+ glEnd();
+ /* back to old line thickness */
+ glLineWidth(old_width);
}
-
- glEnd();
-
- glPointSize(1.0);
+
+ /* Point must be bigger than line thickness */
+ glPointSize(mpath->line_thickness + 1.0);
/* draw little black point at each frame
* NOTE: this is not really visible/noticeable
@@ -197,8 +256,13 @@ void draw_motion_path_instance(Scene *scene,
glVertex3fv(mpv->co);
glEnd();
- /* Draw little white dots at each framestep value */
- UI_ThemeColor(TH_TEXT_HI);
+ /* Draw little white dots at each framestep value or replace with custom color */
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ glColor4fv(mpath->color);
+ }
+ else {
+ UI_ThemeColor(TH_TEXT_HI);
+ }
glBegin(GL_POINTS);
for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize)
glVertex3fv(mpv->co);
@@ -208,11 +272,11 @@ void draw_motion_path_instance(Scene *scene,
* NOTE: this is only done when keyframes are shown, since this adds similar types of clutter
*/
if ((avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) &&
- (sfra < CFRA) && (CFRA <= efra))
+ (sfra < CFRA) && (CFRA <= efra))
{
UI_ThemeColor(TH_CFRAME);
- glPointSize(6.0f);
+ glPointSize(mpath->line_thickness + 5.0);
glBegin(GL_POINTS);
mpv = mpv_start + (CFRA - sfra);
glVertex3fv(mpv->co);
@@ -289,7 +353,13 @@ void draw_motion_path_instance(Scene *scene,
UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col);
col[3] = 255;
- glPointSize(4.0f);
+ /* if custom, point must be bigger than line */
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ glPointSize(mpath->line_thickness + 3.0);
+ }
+ else {
+ glPointSize(4.0f);
+ }
glColor3ubv(col);
glBegin(GL_POINTS);
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index 95a2df68e4a..5208013b6fe 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -1265,7 +1265,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
else {
/* wire */
if (armflag & ARM_POSEMODE) {
- if (constflag) {
+ if (constflag && ((G.f & G_PICKSEL) == 0)) {
/* set constraint colors */
if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
glEnable(GL_BLEND);
@@ -1406,7 +1406,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag
set_ebone_glColor(boneflag);
}
else if (armflag & ARM_POSEMODE) {
- if (constflag) {
+ if (constflag && ((G.f & G_PICKSEL) == 0)) {
/* draw constraint colors */
if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
glEnable(GL_BLEND);
@@ -1903,6 +1903,11 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
}
+ /* custom bone may draw outline double-width */
+ if (arm->flag & ARM_POSEMODE) {
+ glLineWidth(1.0f);
+ }
+
/* draw custom bone shapes as wireframes */
if (!(arm->flag & ARM_NO_CUSTOM) &&
(draw_wire || (dt <= OB_WIRE)) )
@@ -1968,11 +1973,6 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
index = -1;
}
}
-
- /* custom bone may draw outline double-width */
- if (arm->flag & ARM_POSEMODE) {
- glLineWidth(1.0f);
- }
/* wire draw over solid only in posemode */
if ((dt <= OB_WIRE) || (arm->flag & ARM_POSEMODE) || ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
@@ -2360,7 +2360,6 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
/* Draw name */
if (arm->flag & ARM_DRAWNAMES) {
mid_v3_v3v3(vec, eBone->head, eBone->tail);
- glRasterPos3fv(vec);
view3d_cached_text_draw_add(vec, eBone->name, strlen(eBone->name), 10, 0, col);
}
/* Draw additional axes */
@@ -2463,6 +2462,10 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base
if (end <= start)
return;
+ /* prevent infinite loops if this is set to 0 - T49527 */
+ if (arm->ghostsize < 1)
+ arm->ghostsize = 1;
+
stepsize = (float)(arm->ghostsize);
range = (float)(end - start);
@@ -2608,7 +2611,11 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
calc_action_range(adt->action, &start, &end, 0);
if (start == end)
return;
-
+
+ /* prevent infinite loops if this is set to 0 - T49527 */
+ if (arm->ghostsize < 1)
+ arm->ghostsize = 1;
+
stepsize = (float)(arm->ghostsize);
range = (float)(arm->ghostep) * stepsize + 0.5f; /* plus half to make the for loop end correct */
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index ecbfd5c7c85..bbbf8c633bd 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -678,6 +678,7 @@ static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
finalCol[loop_index].r = 255;
finalCol[loop_index].g = 0;
finalCol[loop_index].b = 255;
+ finalCol[loop_index].a = 255;
}
copy_mode = COPY_PREV;
}
@@ -685,6 +686,7 @@ static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
int loop_index = mp->loopstart;
for (j = 0; j < mp->totloop; j++, loop_index++) {
copy_v3_v3_uchar(&finalCol[loop_index].r, Gtexdraw.obcol);
+ finalCol[loop_index].a = 255;
}
copy_mode = COPY_PREV;
}
@@ -1297,6 +1299,13 @@ void draw_mesh_paint_vcolor_faces(DerivedMesh *dm, const bool use_light,
flags |= DM_DRAW_NEED_NORMALS;
}
+ /* Don't show alpha in wire mode. */
+ const bool show_alpha = use_light;
+ if (show_alpha) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
if (me->mloopcol) {
dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data,
DM_DRAW_USE_COLORS | flags);
@@ -1306,6 +1315,10 @@ void draw_mesh_paint_vcolor_faces(DerivedMesh *dm, const bool use_light,
dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, flags);
}
+ if (show_alpha) {
+ glDisable(GL_BLEND);
+ }
+
if (use_light) {
draw_mesh_paint_light_end();
}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 90d33dc5995..5f01092f5b0 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -867,7 +867,7 @@ void view3d_cached_text_draw_add(const float co[3],
memcpy(vos->str, str, alloc_len);
}
-void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, float mat[4][4])
+void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write)
{
RegionView3D *rv3d = ar->regiondata;
ViewCachedString *vos;
@@ -877,9 +877,6 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
/* project first and test */
for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
- if (mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
- mul_m4_v3(mat, vos->vec);
-
if (ED_view3d_project_short_ex(ar,
(vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob,
(vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0,
@@ -1824,16 +1821,16 @@ static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], con
glBegin(mode);
glVertex3fv(near_plane[2]);
- glVertex3fv(near_plane[1]);
- glVertex3fv(far_plane[1]);
glVertex3fv(far_plane[2]);
+ glVertex3fv(far_plane[3]);
+ glVertex3fv(near_plane[3]);
glEnd();
glBegin(mode);
- glVertex3fv(far_plane[0]);
- glVertex3fv(near_plane[0]);
- glVertex3fv(near_plane[3]);
glVertex3fv(far_plane[3]);
+ glVertex3fv(near_plane[3]);
+ glVertex3fv(near_plane[0]);
+ glVertex3fv(far_plane[0]);
glEnd();
}
@@ -4212,7 +4209,6 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if (is_obact && BKE_paint_select_vert_test(ob)) {
const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0;
- glColor3f(0.0f, 0.0f, 0.0f);
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
if (!use_depth) glDisable(GL_DEPTH_TEST);
@@ -5124,7 +5120,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
copy_m4_m4(imat, rv3d->viewinv);
normalize_v3(imat[0]);
normalize_v3(imat[1]);
- /* fall-through */
+ ATTR_FALLTHROUGH;
case PART_DRAW_CROSS:
case PART_DRAW_AXIS:
/* lets calculate the scale: */
@@ -6420,19 +6416,16 @@ static void draw_editnurb(
vec_a[0] = fac;
vec_a[1] = 0.0f;
vec_a[2] = 0.0f;
-
- vec_b[0] = -fac;
- vec_b[1] = 0.0f;
- vec_b[2] = 0.0f;
mul_qt_v3(bevp->quat, vec_a);
- mul_qt_v3(bevp->quat, vec_b);
+ madd_v3_v3fl(vec_a, bevp->dir, -fac);
+
+ reflect_v3_v3v3(vec_b, vec_a, bevp->dir);
+ negate_v3(vec_b);
+
add_v3_v3(vec_a, bevp->vec);
add_v3_v3(vec_b, bevp->vec);
- madd_v3_v3fl(vec_a, bevp->dir, -fac);
- madd_v3_v3fl(vec_b, bevp->dir, -fac);
-
glBegin(GL_LINE_STRIP);
glVertex3fv(vec_a);
glVertex3fv(bevp->vec);
@@ -6476,7 +6469,6 @@ static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *b
Curve *cu = ob->data;
EditFont *ef = cu->editfont;
float vec1[3], vec2[3];
- int selstart, selend;
draw_editfont_textcurs(rv3d, ef->textcurs);
@@ -6529,17 +6521,16 @@ static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *b
setlinestyle(0);
- if (BKE_vfont_select_get(ob, &selstart, &selend) && ef->selboxes) {
- const int seltot = selend - selstart;
+ if (ef->selboxes && ef->selboxes_len) {
float selboxw;
cpack(0xffffff);
set_inverted_drawing(1);
- for (int i = 0; i <= seltot; i++) {
+ for (int i = 0; i < ef->selboxes_len; i++) {
EditFontSelBox *sb = &ef->selboxes[i];
float tvec[3];
- if (i != seltot) {
+ if (i + 1 != ef->selboxes_len) {
if (ef->selboxes[i + 1].y == sb->y)
selboxw = ef->selboxes[i + 1].x - sb->x;
else
@@ -7171,8 +7162,9 @@ static void drawtexspace(Object *ob)
}
/* draws wire outline */
-static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
- const unsigned char ob_wire_col[4])
+static void draw_object_selected_outline(
+ Scene *scene, View3D *v3d, ARegion *ar, Base *base,
+ const unsigned char ob_wire_col[4])
{
RegionView3D *rv3d = ar->regiondata;
Object *ob = base->object;
@@ -7355,7 +7347,7 @@ static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_
theme_id = TH_GROUP_ACTIVE;
if (scene->basact != base) {
- theme_shade = -16;
+ theme_shade = -32;
}
}
else {
@@ -7645,7 +7637,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if ((v3d->flag & V3D_SELECT_OUTLINE) && !render_override && ob->type != OB_MESH) {
if (dt > OB_WIRE && (ob->mode & OB_MODE_EDIT) == 0 && (dflag & DRAW_SCENESET) == 0) {
if (!(ob->dtx & OB_DRAWWIRE) && (ob->flag & SELECT) && !(dflag & (DRAW_PICKING | DRAW_CONSTCOLOR))) {
- drawObjectSelect(scene, v3d, ar, base, ob_wire_col);
+ draw_object_selected_outline(scene, v3d, ar, base, ob_wire_col);
}
}
}
@@ -7831,7 +7823,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
draw_new_particle_system(scene, v3d, rv3d, base, psys, dt, dflag);
}
invert_m4_m4(ob->imat, ob->obmat);
- view3d_cached_text_draw_end(v3d, ar, 0, NULL);
+ view3d_cached_text_draw_end(v3d, ar, 0);
glMultMatrixf(ob->obmat);
@@ -8006,7 +7998,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* return warning, this is cached text draw */
invert_m4_m4(ob->imat, ob->obmat);
- view3d_cached_text_draw_end(v3d, ar, 1, NULL);
+ view3d_cached_text_draw_end(v3d, ar, 1);
/* return warning, clear temp flag */
v3d->flag2 &= ~V3D_SHOW_SOLID_MATCAP;
@@ -8174,6 +8166,50 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
ED_view3d_clear_mats_rv3d(rv3d);
}
+
+/**
+ * Drawing for selection picking,
+ * caller must have called 'GPU_select_load_id(base->selcode)' first.
+ */
+void draw_object_select(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short dflag)
+{
+ BLI_assert(dflag & DRAW_PICKING && dflag & DRAW_CONSTCOLOR);
+ draw_object(scene, ar, v3d, base, dflag);
+
+ /* we draw duplicators for selection too */
+ if ((base->object->transflag & OB_DUPLI)) {
+ ListBase *lb;
+ DupliObject *dob;
+ Base tbase;
+
+ tbase.flag = OB_FROMDUPLI;
+ lb = object_duplilist(G.main->eval_ctx, scene, base->object);
+
+ for (dob = lb->first; dob; dob = dob->next) {
+ float omat[4][4];
+ char dt;
+ short dtx;
+
+ tbase.object = dob->ob;
+ copy_m4_m4(omat, dob->ob->obmat);
+ copy_m4_m4(dob->ob->obmat, dob->mat);
+
+ /* extra service: draw the duplicator in drawtype of parent */
+ /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
+ dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
+ dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
+
+ draw_object(scene, ar, v3d, &tbase, dflag);
+
+ tbase.object->dt = dt;
+ tbase.object->dtx = dtx;
+
+ copy_m4_m4(dob->ob->obmat, omat);
+ }
+ free_object_duplilist(lb);
+ }
+}
+
/* ***************** BACKBUF SEL (BBS) ********* */
static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const float co[3],
@@ -8342,9 +8378,13 @@ static void bbs_mesh_solid_verts(Scene *scene, Object *ob)
DM_update_materials(dm, ob);
- dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_object_material_bind, NULL, me, DM_DRAW_SKIP_HIDDEN);
+ /* Only draw faces to mask out verts, we don't want their selection ID's. */
+ const int G_f_orig = G.f;
+ G.f &= ~G_BACKBUFSEL;
+
+ dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, NULL, NULL, me, DM_DRAW_SKIP_HIDDEN);
- GPU_object_material_unbind();
+ G.f |= (G_f_orig & G_BACKBUFSEL);
bbs_obmode_mesh_verts(ob, dm, 1);
bm_vertoffs = me->totvert + 1;
@@ -8401,8 +8441,8 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
bbs_mesh_wire(em, dm, bm_solidoffs);
bm_wireoffs = bm_solidoffs + em->bm->totedge;
- /* we draw verts if vert select mode or if in transform (for snap). */
- if ((ts->selectmode & SCE_SELECT_VERTEX) || (G.moving & G_TRANSFORM_EDIT)) {
+ /* we draw verts if vert select mode. */
+ if (ts->selectmode & SCE_SELECT_VERTEX) {
bbs_mesh_verts(em, dm, bm_wireoffs);
bm_vertoffs = bm_wireoffs + em->bm->totvert;
}
@@ -8417,8 +8457,8 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
else {
Mesh *me = ob->data;
if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) &&
- /* currently vertex select only supports weight paint */
- (ob->mode & OB_MODE_WEIGHT_PAINT))
+ /* currently vertex select supports weight paint and vertex paint*/
+ ((ob->mode & OB_MODE_WEIGHT_PAINT) || (ob->mode & OB_MODE_VERTEX_PAINT)))
{
bbs_mesh_solid_verts(scene, ob);
}
diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c
index 91adc905816..3f23d4aa09a 100644
--- a/source/blender/editors/space_view3d/drawsimdebug.c
+++ b/source/blender/editors/space_view3d/drawsimdebug.c
@@ -136,9 +136,23 @@ static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4])
glVertex3f(t[0], t[1], t[2]);
}
glEnd();
+
+ /**** strings ****/
+
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ if (elem->type != SIM_DEBUG_ELEM_STRING)
+ continue;
+
+ unsigned char col[4];
+ rgb_float_to_uchar(col, elem->color);
+ col[3] = 255;
+ view3d_cached_text_draw_add(elem->v1, elem->str, strlen(elem->str),
+ 0, V3D_CACHE_TEXT_GLOBALSPACE, col);
+ }
}
-void draw_sim_debug_data(Scene *UNUSED(scene), View3D *UNUSED(v3d), ARegion *ar)
+void draw_sim_debug_data(Scene *UNUSED(scene), View3D *v3d, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
/*Object *ob = base->object;*/
@@ -153,9 +167,11 @@ void draw_sim_debug_data(Scene *UNUSED(scene), View3D *UNUSED(v3d), ARegion *ar)
// glEnable(GL_BLEND);
glPushMatrix();
-
glLoadMatrixf(rv3d->viewmat);
+
+ view3d_cached_text_draw_begin();
draw_sim_debug_elements(_sim_debug_data, imat);
+ view3d_cached_text_draw_end(v3d, ar, false);
glPopMatrix();
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 27ecbf83db5..c076bfb4aa4 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -737,7 +737,7 @@ static void add_streamline(float (*verts)[3], float(*colors)[3], float center[3]
copy_v3_v3(verts[(*offset)++], center);
}
-typedef void (*vector_draw_func)(float(*)[3], float(*)[3], float*, float*, float, float, int*);
+typedef void (*vector_draw_func)(float(*)[3], float(*)[3], float *, float *, float, float, int *);
#endif /* WITH_SMOKE */
void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3])
@@ -774,8 +774,8 @@ void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3])
float min[3] = {
domain->p0[0] - domain->cell_size[0] * domain->adapt_res,
- domain->p0[1] - domain->cell_size[1] * domain->adapt_res,
- domain->p0[2] - domain->cell_size[2] * domain->adapt_res,
+ domain->p0[1] - domain->cell_size[1] * domain->adapt_res,
+ domain->p0[2] - domain->cell_size[2] * domain->adapt_res,
};
int num_points_v[3] = {
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 075b1faf502..996506a9cf7 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -180,8 +180,8 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
View3D *v3d = (View3D *)sa->spacedata.first;
if (ar) {
- RegionView3D *rv3d = ar->regiondata;
- if (rv3d && (rv3d->viewlock & RV3D_LOCKED) == 0) {
+ RegionView3D *rv3d;
+ if ((ar->regiontype == RGN_TYPE_WINDOW) && (rv3d = ar->regiondata) && (rv3d->viewlock & RV3D_LOCKED) == 0) {
*r_v3d = v3d;
*r_ar = ar;
return true;
@@ -869,6 +869,7 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
case ND_CONSTRAINT:
case ND_KEYS:
case ND_PARTICLE:
+ case ND_POINTCACHE:
case ND_LOD:
ED_region_tag_redraw(ar);
break;
@@ -1256,21 +1257,6 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot
}
break;
}
-
- /* removed since BKE_image_user_frame_calc is now called in view3d_draw_bgpic because screen_ops doesnt call the notifier. */
-#if 0
- if (wmn->category == NC_SCENE && wmn->data == ND_FRAME) {
- View3D *v3d = area->spacedata.first;
- BGpic *bgpic = v3d->bgpicbase.first;
-
- for (; bgpic; bgpic = bgpic->next) {
- if (bgpic->ima) {
- Scene *scene = wmn->reference;
- BKE_image_user_frame_calc(&bgpic->iuser, scene->r.cfra, 0);
- }
- }
- }
-#endif
}
const char *view3d_context_dir[] = {
@@ -1426,33 +1412,31 @@ static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_i
}
}
}
- 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
+ /* Values in local-view aren't used, see: T52663 */
+ if (is_local == false) {
+ /* Skip 'v3d->defmaterial', it's not library data. */
- 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 *)v3d->ob_centre == old_id) {
+ v3d->ob_centre = (Object *)new_id;
+ /* Otherwise, bonename may remain valid... We could be smart and check this, too? */
+ if (new_id == NULL) {
+ v3d->ob_centre_bone[0] = '\0';
}
- if ((ID *)bgpic->clip == old_id) {
- bgpic->clip = (MovieClip *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
+ }
+
+ 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);
+ }
}
}
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index b9c8c98b62f..34e01405e7e 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -476,7 +476,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
totedgedata == 1 ? IFACE_("Crease:") : IFACE_("Mean Crease:"),
0, yi -= buth + but_margin, 200, buth,
- &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by SubSurf modifier"));
+ &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by the Subdivision Surface modifier"));
}
}
/* Curve... */
@@ -491,7 +491,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
else if (totcurvedata > 1) {
uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
0, yi -= buth + but_margin, 200, buth,
- &(tfp->ve_median[C_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for SoftBody Goal"));
+ &(tfp->ve_median[C_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal"));
uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Radius:"),
0, yi -= buth + but_margin, 200, buth,
&(tfp->ve_median[C_RADIUS]), 0.0, 100.0, 1, 3, TIP_("Radius of curve control points"));
@@ -509,7 +509,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
else if (totlattdata > 1) {
uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
0, yi -= buth + but_margin, 200, buth,
- &(tfp->ve_median[L_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for SoftBody Goal"));
+ &(tfp->ve_median[L_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal"));
}
UI_block_align_end(block);
@@ -814,10 +814,6 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
if (dv && dv->totweight) {
ToolSettings *ts = scene->toolsettings;
- wmOperatorType *ot_weight_set_active = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true);
- wmOperatorType *ot_weight_paste = WM_operatortype_find("OBJECT_OT_vertex_weight_paste", true);
- wmOperatorType *ot_weight_delete = WM_operatortype_find("OBJECT_OT_vertex_weight_delete", true);
-
wmOperatorType *ot;
PointerRNA op_ptr, tools_ptr;
PointerRNA *but_ptr;
@@ -856,7 +852,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
/* The Weight Group Name */
- ot = ot_weight_set_active;
+ ot = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true);
but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, dg->name,
xco, yco, (x = UI_UNIT_X * 5), UI_UNIT_Y, "");
but_ptr = UI_but_operator_ptr_get(but);
@@ -882,23 +878,16 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
xco += x;
/* The weight group paste function */
-
- ot = ot_weight_paste;
- WM_operator_properties_create_ptr(&op_ptr, ot);
- RNA_int_set(&op_ptr, "weight_group", i);
icon = (locked) ? ICON_BLANK1 : ICON_PASTEDOWN;
- uiItemFullO_ptr(row, ot, "", icon, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+ op_ptr = uiItemFullO(row, "OBJECT_OT_vertex_weight_paste", "", icon, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_int_set(&op_ptr, "weight_group", i);
/* The weight entry delete function */
-
- ot = ot_weight_delete;
- WM_operator_properties_create_ptr(&op_ptr, ot);
- RNA_int_set(&op_ptr, "weight_group", i);
icon = (locked) ? ICON_LOCKED : ICON_X;
- uiItemFullO_ptr(row, ot, "", icon, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+ op_ptr = uiItemFullO(row, "OBJECT_OT_vertex_weight_delete", "", icon, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_int_set(&op_ptr, "weight_group", i);
yco -= UI_UNIT_Y;
-
}
}
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 000d1fe4810..56508ea989a 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -100,11 +100,13 @@
#include "GPU_material.h"
#include "GPU_compositing.h"
#include "GPU_extensions.h"
+#include "GPU_select.h"
#include "view3d_intern.h" /* own include */
/* prototypes */
-static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar);
+static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d);
+static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar, const rcti *rect);
static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
float winmat[4][4], const char *viewname);
@@ -2023,6 +2025,35 @@ static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const
glDepthMask(GL_TRUE);
}
+/* clears zbuffer and draws it over,
+ * note that in the select version we don't care about transparent flag as with regular drawing */
+static void view3d_draw_xray_select(Scene *scene, ARegion *ar, View3D *v3d, bool *clear)
+{
+ /* Not ideal, but we need to read from the previous depths before clearing
+ * otherwise we could have a function to load the depths after drawing.
+ *
+ * Clearing the depth buffer isn't all that common between drawing objects so accept this for now.
+ */
+ if (U.gpu_select_pick_deph) {
+ GPU_select_load_id(-1);
+ }
+
+ View3DAfter *v3da;
+ if (*clear && v3d->zbuf) {
+ glClear(GL_DEPTH_BUFFER_BIT);
+ *clear = false;
+ }
+
+ v3d->xray = true;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
+ if (GPU_select_load_id(v3da->base->selcol)) {
+ draw_object_select(scene, ar, v3d, v3da->base, v3da->dflag);
+ }
+ MEM_freeN(v3da);
+ }
+ v3d->xray = false;
+}
+
/* *********************** */
/*
@@ -2341,17 +2372,11 @@ void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d)
short zbuf = v3d->zbuf;
RegionView3D *rv3d = ar->regiondata;
- view3d_winmatrix_set(ar, v3d, NULL);
- view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */
-
- mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
- invert_m4_m4(rv3d->persinv, rv3d->persmat);
- invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
+ /* Setup view matrix. */
+ ED_view3d_draw_setup_view(NULL, scene, ar, v3d, rv3d->viewmat, rv3d->winmat, NULL);
glClear(GL_DEPTH_BUFFER_BIT);
- glLoadMatrixf(rv3d->viewmat);
-
v3d->zbuf = true;
glEnable(GL_DEPTH_TEST);
@@ -2360,46 +2385,15 @@ void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d)
}
v3d->zbuf = zbuf;
-
}
-void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride)
+static void view3d_draw_depth_loop(Scene *scene, ARegion *ar, View3D *v3d)
{
- RegionView3D *rv3d = ar->regiondata;
Base *base;
- short zbuf = v3d->zbuf;
- short flag = v3d->flag;
- float glalphaclip = U.glalphaclip;
- int obcenter_dia = U.obcenter_dia;
+
/* no need for color when drawing depth buffer */
const short dflag_depth = DRAW_CONSTCOLOR;
- /* temp set drawtype to solid */
-
- /* Setting these temporarily is not nice */
- v3d->flag &= ~V3D_SELECT_OUTLINE;
- U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */
- U.obcenter_dia = 0;
-
- view3d_winmatrix_set(ar, v3d, NULL);
- view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */
-
- mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
- invert_m4_m4(rv3d->persinv, rv3d->persmat);
- invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
-
- glClear(GL_DEPTH_BUFFER_BIT);
-
- glLoadMatrixf(rv3d->viewmat);
-
- if (rv3d->rflag & RV3D_CLIPPING) {
- ED_view3d_clipping_set(rv3d);
- }
- /* get surface depth without bias */
- rv3d->rflag |= RV3D_ZOFFSET_DISABLED;
- v3d->zbuf = true;
- glEnable(GL_DEPTH_TEST);
-
/* draw set first */
if (scene->set) {
Scene *sce_iter;
@@ -2473,7 +2467,43 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover
glDepthMask(mask_orig);
}
+}
+
+void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride)
+{
+ struct bThemeState theme_state;
+ RegionView3D *rv3d = ar->regiondata;
+ short zbuf = v3d->zbuf;
+ short flag = v3d->flag;
+ float glalphaclip = U.glalphaclip;
+ int obcenter_dia = U.obcenter_dia;
+ /* temp set drawtype to solid */
+ /* Setting these temporarily is not nice */
+ v3d->flag &= ~V3D_SELECT_OUTLINE;
+ U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */
+ U.obcenter_dia = 0;
+
+ /* Tools may request depth outside of regular drawing code. */
+ UI_Theme_Store(&theme_state);
+ UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
+
+ /* Setup view matrix. */
+ ED_view3d_draw_setup_view(NULL, scene, ar, v3d, rv3d->viewmat, rv3d->winmat, NULL);
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ if (rv3d->rflag & RV3D_CLIPPING) {
+ ED_view3d_clipping_set(rv3d);
+ }
+ /* get surface depth without bias */
+ rv3d->rflag |= RV3D_ZOFFSET_DISABLED;
+
+ v3d->zbuf = true;
+ glEnable(GL_DEPTH_TEST);
+
+ view3d_draw_depth_loop(scene, ar, v3d);
+
if (rv3d->rflag & RV3D_CLIPPING) {
ED_view3d_clipping_disable();
}
@@ -2485,6 +2515,60 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover
U.glalphaclip = glalphaclip;
v3d->flag = flag;
U.obcenter_dia = obcenter_dia;
+
+ UI_Theme_Restore(&theme_state);
+}
+
+void ED_view3d_draw_select_loop(
+ ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar,
+ bool use_obedit_skip, bool use_nearest)
+{
+ short code = 1;
+ const short dflag = DRAW_PICKING | DRAW_CONSTCOLOR;
+
+ if (vc->obedit && vc->obedit->type == OB_MBALL) {
+ draw_object(scene, ar, v3d, BASACT, dflag);
+ }
+ else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
+ /* if not drawing sketch, draw bones */
+ if (!BDR_drawSketchNames(vc)) {
+ draw_object(scene, ar, v3d, BASACT, dflag);
+ }
+ }
+ else {
+ Base *base;
+
+ for (base = scene->base.first; base; base = base->next) {
+ if (base->lay & v3d->lay) {
+
+ if ((base->object->restrictflag & OB_RESTRICT_SELECT) ||
+ (use_obedit_skip && (scene->obedit->data == base->object->data)))
+ {
+ base->selcol = 0;
+ }
+ else {
+ base->selcol = code;
+
+ if (use_nearest && (base->object->dtx & OB_DRAWXRAY)) {
+ ED_view3d_after_add(&v3d->afterdraw_xray, base, dflag);
+ }
+ else {
+ if (GPU_select_load_id(code)) {
+ draw_object_select(scene, ar, v3d, base, dflag);
+ }
+ }
+ code++;
+ }
+ }
+ }
+
+ if (use_nearest) {
+ bool xrayclear = true;
+ if (v3d->afterdraw_xray.first) {
+ view3d_draw_xray_select(scene, ar, v3d, &xrayclear);
+ }
+ }
+ }
}
typedef struct View3DShadow {
@@ -2515,7 +2599,7 @@ static void gpu_render_lamp_update(Scene *scene, View3D *v3d,
if (layers &&
GPU_lamp_has_shadow_buffer(lamp) &&
/* keep last, may do string lookup */
- GPU_lamp_override_visible(lamp, srl, NULL))
+ GPU_lamp_visible(lamp, srl, NULL))
{
shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow");
shadow->lamp = lamp;
@@ -2655,16 +2739,16 @@ CustomDataMask ED_view3d_screen_datamask(const bScreen *screen)
/**
* \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
*/
-void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
+void ED_view3d_update_viewmat(
+ Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect)
{
RegionView3D *rv3d = ar->regiondata;
- rctf cameraborder;
/* setup window matrices */
if (winmat)
copy_m4_m4(rv3d->winmat, winmat);
else
- view3d_winmatrix_set(ar, v3d, NULL);
+ view3d_winmatrix_set(ar, v3d, rect);
/* setup view matrix */
if (viewmat)
@@ -2672,7 +2756,7 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view
else
view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */
- /* update utilitity matrices */
+ /* update utility matrices */
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
invert_m4_m4(rv3d->persinv, rv3d->persmat);
invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
@@ -2681,6 +2765,7 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view
/* store window coordinates scaling/offset */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ rctf cameraborder;
ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false);
rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder);
rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder);
@@ -2692,8 +2777,17 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view
rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f;
rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f;
}
-
- /* calculate pixelsize factor once, is used for lamps and obcenters */
+
+ /**
+ * Calculate pixel-size factor once, is used for lamps and object centers.
+ * Used by #ED_view3d_pixel_size and typically not accessed directly.
+ *
+ * \note #BKE_camera_params_compute_viewplane' also calculates a pixel-size value,
+ * passed to #RE_SetPixelSize, in ortho mode this is compatible with this value,
+ * but in perspective mode its offset by the near-clip.
+ *
+ * 'RegionView3D.pixsize' is used for viewport drawing, not rendering.
+ */
{
/* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])'
* because of float point precision problems at large values [#23908] */
@@ -2917,11 +3011,12 @@ static void view3d_draw_objects(
}
}
-static void view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
+static void view3d_main_region_setup_view(
+ Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect)
{
RegionView3D *rv3d = ar->regiondata;
- ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat);
+ ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat, rect);
/* set for opengl */
glMatrixMode(GL_PROJECTION);
@@ -2946,7 +3041,7 @@ struct RV3DMatrixStore {
float pixsize;
};
-void *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d)
+struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d)
{
struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__);
copy_m4_m4(rv3dmat->winmat, rv3d->winmat);
@@ -2959,9 +3054,8 @@ void *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d)
return (void *)rv3dmat;
}
-void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, void *rv3dmat_pt)
+void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat)
{
- struct RV3DMatrixStore *rv3dmat = rv3dmat_pt;
copy_m4_m4(rv3d->winmat, rv3dmat->winmat);
copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat);
copy_m4_m4(rv3d->persmat, rv3dmat->persmat);
@@ -3105,7 +3199,7 @@ void ED_view3d_draw_offscreen(
if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera)
view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname);
else
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, NULL);
/* framebuffer fx needed, we need to draw offscreen first */
if (v3d->fx_settings.fx_flag && fx) {
@@ -3168,6 +3262,23 @@ void ED_view3d_draw_offscreen(
}
/**
+ * Set the correct matrices
+ */
+void ED_view3d_draw_setup_view(
+ wmWindow *win, Scene *scene, ARegion *ar, View3D *v3d, float viewmat[4][4], float winmat[4][4], const rcti *rect)
+{
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* Setup the view matrix. */
+ if (view3d_stereo3d_active(win, scene, v3d, rv3d)) {
+ view3d_stereo3d_setup(scene, v3d, ar, rect);
+ }
+ else {
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, rect);
+ }
+}
+
+/**
* Utility func for ED_view3d_draw_offscreen
*
* \param ofs: Optional off-screen buffer, can be NULL.
@@ -3534,7 +3645,7 @@ static bool view3d_main_region_draw_engine(const bContext *C, Scene *scene,
}
/* setup view matrices */
- view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL);
+ view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL, NULL);
/* background draw */
ED_region_pixelspace(ar);
@@ -3601,26 +3712,37 @@ static void view3d_main_region_draw_engine_info(View3D *v3d, RegionView3D *rv3d,
ED_region_info_draw(ar, rv3d->render_engine->text, fill_color, true);
}
-static bool view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d)
+static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d)
{
- wmWindow *win = CTX_wm_window(C);
-
- if ((scene->r.scemode & R_MULTIVIEW) == 0)
- return false;
-
- if (WM_stereo3d_enabled(win, true) == false)
+ if ((scene->r.scemode & R_MULTIVIEW) == 0) {
return false;
+ }
- if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB)
+ if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) {
return false;
+ }
- if (scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) {
- if (v3d->stereo3d_camera == STEREO_MONO_ID)
+ switch (v3d->stereo3d_camera) {
+ case STEREO_MONO_ID:
return false;
-
- return BKE_scene_multiview_is_stereo3d(&scene->r);
+ break;
+ case STEREO_3D_ID:
+ /* win will be NULL when calling this from the selection or draw loop. */
+ if ((win == NULL) || (WM_stereo3d_enabled(win, true) == false)) {
+ return false;
+ }
+ if (((scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) != 0) &&
+ !BKE_scene_multiview_is_stereo3d(&scene->r))
+ {
+ return false;
+ }
+ break;
+ /* We always need the stereo calculation for left and right cameras. */
+ case STEREO_LEFT_ID:
+ case STEREO_RIGHT_ID:
+ default:
+ break;
}
-
return true;
}
@@ -3632,7 +3754,7 @@ static bool view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d,
* we do a small hack to replace it temporarily so we don't need to change the
* view3d)main_region_setup_view() code to account for that.
*/
-static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar)
+static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar, const rcti *rect)
{
bool is_left;
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
@@ -3658,7 +3780,7 @@ static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar)
data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname);
BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL, rect);
data->shiftx = shiftx;
BLI_unlock_thread(LOCK_VIEW3D);
@@ -3672,7 +3794,7 @@ static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar)
v3d->camera = camera;
BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL, rect);
v3d->camera = view_ob;
BLI_unlock_thread(LOCK_VIEW3D);
@@ -3688,14 +3810,14 @@ static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *
const bool is_left = STREQ(viewname, STEREO_LEFT_NAME);
BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, NULL);
}
else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
float viewmat[4][4];
Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, NULL);
}
}
@@ -3733,11 +3855,8 @@ static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, Vie
GPU_default_lights();
}
- /* setup the view matrix */
- if (view3d_stereo3d_active(C, scene, v3d, rv3d))
- view3d_stereo3d_setup(scene, v3d, ar);
- else
- view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL);
+ /* Setup the view matrix. */
+ ED_view3d_draw_setup_view(CTX_wm_window(C), scene, ar, v3d, NULL, NULL, NULL);
rv3d->rflag &= ~RV3D_IS_GAME_ENGINE;
#ifdef WITH_GAMEENGINE
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 9e41ad6a8f6..97fcca11962 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -85,24 +85,13 @@
#include "view3d_intern.h" /* own include */
+static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar);
+
bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
}
-static bool view3d_operator_offset_lock_check(bContext *C, wmOperator *op)
-{
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (ED_view3d_offset_lock_check(v3d, rv3d)) {
- BKE_report(op->reports, RPT_WARNING, "View offset is locked");
- return true;
- }
- else {
- return false;
- }
-}
-
/* ********************** view3d_edit: view manipulations ********************* */
/**
@@ -566,22 +555,20 @@ typedef struct ViewOpsData {
static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3])
{
- float x, y, radius, d, z, t;
-
- radius = TRACKBALLSIZE;
+ const float radius = TRACKBALLSIZE;
+ const float t = radius / (float)M_SQRT2;
+ float x, y, z, d;
/* normalize x and y */
x = BLI_rcti_cent_x(rect) - mx;
x /= (float)(BLI_rcti_size_x(rect) / 4);
y = BLI_rcti_cent_y(rect) - my;
y /= (float)(BLI_rcti_size_y(rect) / 2);
-
d = sqrtf(x * x + y * y);
- if (d < radius * (float)M_SQRT1_2) { /* Inside sphere */
+ if (d < t) { /* Inside sphere */
z = sqrtf(radius * radius - d * d);
}
else { /* On hyperbola */
- t = radius / (float)M_SQRT2;
z = t * t / d;
}
@@ -712,16 +699,72 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
return is_set;
}
+enum eViewOpsOrbit {
+ VIEWOPS_ORBIT_SELECT = (1 << 0),
+ VIEWOPS_ORBIT_DEPTH = (1 << 1),
+};
+
+static enum eViewOpsOrbit viewops_orbit_mode_ex(bool use_select, bool use_depth)
+{
+ enum eViewOpsOrbit flag = 0;
+ if (use_select) {
+ flag |= VIEWOPS_ORBIT_SELECT;
+ }
+ if (use_depth) {
+ flag |= VIEWOPS_ORBIT_DEPTH;
+ }
+
+ return flag;
+}
+
+static enum eViewOpsOrbit viewops_orbit_mode(void)
+{
+ return viewops_orbit_mode_ex(
+ (U.uiflag & USER_ORBIT_SELECTION) != 0,
+ (U.uiflag & USER_ZBUF_ORBIT) != 0);
+}
+
/**
* Calculate the values for #ViewOpsData
+ *
+ * \param use_ensure_persp: When enabled run #view3d_ensure_persp this may switch out of
+ * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled.
+ * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common
+ * so we don't want it to trigger auto-perspective).
*/
-static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *event,
- const bool use_orbit_select,
- const bool use_orbit_zbuf)
+static void viewops_data_create_ex(
+ bContext *C, wmOperator *op, const wmEvent *event,
+ bool use_ensure_persp, enum eViewOpsOrbit orbit_mode)
{
ViewOpsData *vod = op->customdata;
RegionView3D *rv3d = vod->rv3d;
+ /* we need the depth info before changing any viewport options */
+ if (orbit_mode & VIEWOPS_ORBIT_DEPTH) {
+ float fallback_depth_pt[3];
+
+ view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
+
+ negate_v3_v3(fallback_depth_pt, rv3d->ofs);
+
+ vod->use_dyn_ofs = ED_view3d_autodist(
+ vod->scene, vod->ar, vod->v3d,
+ event->mval, vod->dyn_ofs, true, fallback_depth_pt);
+ }
+ else {
+ vod->use_dyn_ofs = false;
+ }
+
+ if (use_ensure_persp) {
+ if (view3d_ensure_persp(vod->v3d, vod->ar)) {
+ /* If we're switching from camera view to the perspective one,
+ * need to tag viewport update, so camera vuew and borders
+ * are properly updated.
+ */
+ ED_region_tag_redraw(vod->ar);
+ }
+ }
+
/* set the view from the camera, if view locking is enabled.
* we may want to make this optional but for now its needed always */
ED_view3d_camera_lock_init(vod->v3d, vod->rv3d);
@@ -733,28 +776,19 @@ static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *e
vod->origx = vod->oldx = event->x;
vod->origy = vod->oldy = event->y;
vod->origkey = event->type; /* the key that triggered the operator. */
- vod->use_dyn_ofs = false;
copy_v3_v3(vod->ofs, rv3d->ofs);
- if (use_orbit_select) {
-
- vod->use_dyn_ofs = true;
-
- view3d_orbit_calc_center(C, vod->dyn_ofs);
-
- negate_v3(vod->dyn_ofs);
+ if (orbit_mode & VIEWOPS_ORBIT_SELECT) {
+ float ofs[3];
+ if (view3d_orbit_calc_center(C, ofs) || (vod->use_dyn_ofs == false)) {
+ vod->use_dyn_ofs = true;
+ negate_v3_v3(vod->dyn_ofs, ofs);
+ orbit_mode &= ~VIEWOPS_ORBIT_DEPTH;
+ }
}
- else if (use_orbit_zbuf) {
- Scene *scene = CTX_data_scene(C);
- float fallback_depth_pt[3];
-
- view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
-
- negate_v3_v3(fallback_depth_pt, rv3d->ofs);
- if ((vod->use_dyn_ofs = ED_view3d_autodist(scene, vod->ar, vod->v3d,
- event->mval, vod->dyn_ofs, true, fallback_depth_pt)))
- {
+ if (orbit_mode & VIEWOPS_ORBIT_DEPTH) {
+ if (vod->use_dyn_ofs) {
if (rv3d->is_persp) {
float my_origin[3]; /* original G.vd->ofs */
float my_pivot[3]; /* view */
@@ -789,7 +823,7 @@ static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *e
(float)vod->ar->winx / 2.0f,
(float)vod->ar->winy / 2.0f};
- ED_view3d_win_to_3d(vod->ar, vod->dyn_ofs, mval_ar_mid, rv3d->ofs);
+ ED_view3d_win_to_3d(vod->v3d, vod->ar, vod->dyn_ofs, mval_ar_mid, rv3d->ofs);
negate_v3(rv3d->ofs);
}
negate_v3(vod->dyn_ofs);
@@ -823,12 +857,10 @@ static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *e
rv3d->rflag |= RV3D_NAVIGATING;
}
-static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event)
+static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event, bool use_ensure_persp)
{
- viewops_data_create_ex(
- C, op, event,
- (U.uiflag & USER_ORBIT_SELECTION) != 0,
- (U.uiflag & USER_ZBUF_ORBIT) != 0);
+ enum eViewOpsOrbit orbit_mode = viewops_orbit_mode();
+ viewops_data_create_ex(C, op, event, use_ensure_persp, orbit_mode);
}
static void viewops_data_free(bContext *C, wmOperator *op)
@@ -1234,16 +1266,7 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
- /* switch from camera view when: */
- if (view3d_ensure_persp(vod->v3d, vod->ar)) {
- /* If we're switching from camera view to the perspective one,
- * need to tag viewport update, so camera vuew and borders
- * are properly updated.
- */
- ED_region_tag_redraw(vod->ar);
- }
-
- viewops_data_create(C, op, event);
+ viewops_data_create(C, op, event, true);
if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) {
/* Rotate direction we keep always same */
@@ -1652,8 +1675,9 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const wmNDOFMotionData *ndof = event->customdata;
viewops_data_alloc(C, op);
- viewops_data_create_ex(C, op, event,
- (U.uiflag & USER_ORBIT_SELECTION) != 0, false);
+ viewops_data_create_ex(
+ C, op, event,
+ false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false));
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -1720,8 +1744,9 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
const wmNDOFMotionData *ndof = event->customdata;
viewops_data_alloc(C, op);
- viewops_data_create_ex(C, op, event,
- (U.uiflag & USER_ORBIT_SELECTION) != 0, false);
+ viewops_data_create_ex(
+ C, op, event,
+ false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false));
vod = op->customdata;
@@ -2035,7 +2060,7 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* makes op->customdata */
viewops_data_alloc(C, op);
- viewops_data_create(C, op, event);
+ viewops_data_create(C, op, event, false);
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -2516,7 +2541,7 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* makes op->customdata */
viewops_data_alloc(C, op);
- viewops_data_create(C, op, event);
+ viewops_data_create(C, op, event, false);
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -2598,6 +2623,19 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
/* ************************ viewdolly ******************************** */
+static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op)
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (ED_view3d_offset_lock_check(v3d, rv3d)) {
+ BKE_report(op->reports, RPT_WARNING, "Cannot dolly when the view offset is locked");
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
static void view_dolly_mouseloc(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac)
{
RegionView3D *rv3d = ar->regiondata;
@@ -2748,7 +2786,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
- if (view3d_operator_offset_lock_check(C, op))
+ if (viewdolly_offset_lock_check(C, op))
return OPERATOR_CANCELLED;
/* makes op->customdata */
@@ -2776,7 +2814,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_region_tag_redraw(vod->ar);
}
- viewops_data_create(C, op, event);
+ viewops_data_create(C, op, event, false);
/* if one or the other zoom position aren't set, set from event */
@@ -3289,7 +3327,7 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev
else {
/* fallback to simple pan */
negate_v3_v3(new_ofs, rv3d->ofs);
- ED_view3d_win_to_3d_int(ar, new_ofs, event->mval, new_ofs);
+ ED_view3d_win_to_3d_int(v3d, ar, new_ofs, event->mval, new_ofs);
}
negate_v3(new_ofs);
ED_view3d_smooth_view(
@@ -4066,6 +4104,9 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
mul_qt_qtqt(quat_new, rv3d->viewquat, quat_mul);
+ /* avoid precision loss over time */
+ normalize_qt(quat_new);
+
if (view_opposite != RV3D_VIEW_USER) {
rv3d->view = view_opposite;
/* avoid float in-precision, just get a new orientation */
@@ -4132,6 +4173,10 @@ static void view_roll_angle(ARegion *ar, float quat[4], const float orig_quat[4]
axis_angle_normalized_to_quat(quat_mul, dvec, angle);
mul_qt_qtqt(quat, orig_quat, quat_mul);
+
+ /* avoid precision loss over time */
+ normalize_qt(quat);
+
rv3d->view = RV3D_VIEW_USER;
}
@@ -4293,7 +4338,7 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
else {
/* makes op->customdata */
viewops_data_alloc(C, op);
- viewops_data_create(C, op, event);
+ viewops_data_create(C, op, event, false);
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -4359,41 +4404,24 @@ static EnumPropertyItem prop_view_pan_items[] = {
{0, NULL, 0, NULL, NULL}
};
-static int viewpan_exec(bContext *C, wmOperator *op)
+static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- float vec[3];
- const float co_zero[3] = {0.0f};
- float mval_f[2] = {0.0f, 0.0f};
- float zfac;
- int pandir;
-
- if (view3d_operator_offset_lock_check(C, op))
- return OPERATOR_CANCELLED;
+ int x = 0, y = 0;
+ int pandir = RNA_enum_get(op->ptr, "type");
- pandir = RNA_enum_get(op->ptr, "type");
+ if (pandir == V3D_VIEW_PANRIGHT) { x = -32; }
+ else if (pandir == V3D_VIEW_PANLEFT) { x = 32; }
+ else if (pandir == V3D_VIEW_PANUP) { y = -25; }
+ else if (pandir == V3D_VIEW_PANDOWN) { y = 25; }
- ED_view3d_camera_lock_init(v3d, rv3d);
-
- zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL);
- if (pandir == V3D_VIEW_PANRIGHT) { mval_f[0] = -32.0f; }
- else if (pandir == V3D_VIEW_PANLEFT) { mval_f[0] = 32.0f; }
- else if (pandir == V3D_VIEW_PANUP) { mval_f[1] = -25.0f; }
- else if (pandir == V3D_VIEW_PANDOWN) { mval_f[1] = 25.0f; }
- ED_view3d_win_to_delta(ar, mval_f, vec, zfac);
- add_v3_v3(rv3d->ofs, vec);
-
- if (rv3d->viewlock & RV3D_BOXVIEW)
- view3d_boxview_sync(sa, ar);
-
- ED_view3d_depth_tag_update(rv3d);
+ viewops_data_alloc(C, op);
+ viewops_data_create(C, op, event, false);
+ ViewOpsData *vod = op->customdata;
- ED_view3d_camera_lock_sync(v3d, rv3d);
+ viewmove_apply(vod, vod->oldx + x, vod->oldy + y);
- ED_region_tag_redraw(ar);
+ ED_view3d_depth_tag_update(vod->rv3d);
+ viewops_data_free(C, op);
return OPERATOR_FINISHED;
}
@@ -4406,7 +4434,7 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot)
ot->idname = "VIEW3D_OT_view_pan";
/* api callbacks */
- ot->exec = viewpan_exec;
+ ot->invoke = viewpan_invoke;
ot->poll = ED_operator_region_view3d_active;
/* flags */
@@ -4708,7 +4736,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
if (depth_used == false) {
float depth_pt[3];
copy_v3_v3(depth_pt, fp);
- ED_view3d_win_to_3d_int(ar, depth_pt, mval, fp);
+ ED_view3d_win_to_3d_int(v3d, ar, depth_pt, mval, fp);
}
}
@@ -4729,13 +4757,20 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2])
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
- float co_curr[2], co_prev[2];
+ if (U.uiflag & USER_LOCK_CURSOR_ADJUST) {
- if ((ED_view3d_project_float_global(ar, fp_prev, co_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
- (ED_view3d_project_float_global(ar, fp_curr, co_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
- {
- rv3d->ofs_lock[0] += (co_curr[0] - co_prev[0]) / (ar->winx * 0.5f);
- rv3d->ofs_lock[1] += (co_curr[1] - co_prev[1]) / (ar->winy * 0.5f);
+ float co_curr[2], co_prev[2];
+
+ if ((ED_view3d_project_float_global(ar, fp_prev, co_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
+ (ED_view3d_project_float_global(ar, fp_curr, co_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
+ {
+ rv3d->ofs_lock[0] += (co_curr[0] - co_prev[0]) / (ar->winx * 0.5f);
+ rv3d->ofs_lock[1] += (co_curr[1] - co_prev[1]) / (ar->winy * 0.5f);
+ }
+ }
+ else {
+ /* Cursor may be outside of the view, prevent it getting 'lost', see: T40353 & T45301 */
+ zero_v2(rv3d->ofs_lock);
}
}
@@ -4782,13 +4817,10 @@ static int manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
- /* only no modifier or shift */
- if (event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
-
/* note; otherwise opengl won't work */
view3d_operator_needs_opengl(C);
- if (0 == BIF_do_manipulator(C, event, op))
+ if (BIF_do_manipulator(C, event, op) == 0)
return OPERATOR_PASS_THROUGH;
return OPERATOR_FINISHED;
@@ -4796,6 +4828,7 @@ static int manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void VIEW3D_OT_manipulator(wmOperatorType *ot)
{
+ PropertyRNA *prop;
/* identifiers */
ot->name = "3D Manipulator";
@@ -4809,6 +4842,10 @@ void VIEW3D_OT_manipulator(wmOperatorType *ot)
/* properties to pass to transform */
Transform_Properties(ot, P_CONSTRAINT);
+
+ prop = RNA_def_boolean(ot->srna, "use_planar_constraint", false, "Planar Constraint", "Limit the transformation to the "
+ "two axes that have not been clicked (translate/scale only)");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -4897,11 +4934,7 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg
rect.ymax = mval[1] + 1;
}
else {
- rect.xmax = mval[0] + margin;
- rect.ymax = mval[1] + margin;
-
- rect.xmin = mval[0] - margin;
- rect.ymin = mval[1] - margin;
+ BLI_rcti_init_pt_radius(&rect, mval, margin);
}
view3d_update_depths_rect(ar, &depth_temp, &rect);
@@ -4957,7 +4990,7 @@ bool ED_view3d_autodist(
}
if (fallback_depth_pt) {
- ED_view3d_win_to_3d_int(ar, fallback_depth_pt, mval, mouse_worldloc);
+ ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc);
return true;
}
else {
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 0713377d210..70caee66b29 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -337,20 +337,20 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
/* Draw type */
uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- if (obedit == NULL && is_paint) {
- if (ob->mode & OB_MODE_ALL_PAINT) {
- /* Only for Weight Paint. makes no sense in other paint modes. */
- row = uiLayoutRow(layout, true);
- uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- }
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ if (!ob || ELEM(ob->mode, OB_MODE_OBJECT, OB_MODE_POSE, OB_MODE_WEIGHT_PAINT)) {
+ uiItemR(row, &v3dptr, "use_pivot_point_align", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ }
+ if (obedit == NULL && is_paint) {
/* Manipulators aren't used in paint modes */
if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) {
/* masks aren't used for sculpt and particle painting */
PointerRNA meshptr;
RNA_pointer_create(ob->data, &RNA_Mesh, ob->data, &meshptr);
- if (ob->mode & (OB_MODE_TEXTURE_PAINT | OB_MODE_VERTEX_PAINT)) {
+ if (ob->mode & (OB_MODE_TEXTURE_PAINT)) {
uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
}
else {
@@ -361,17 +361,6 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
}
}
else {
- row = uiLayoutRow(layout, true);
- uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
-
- /* pose/object only however we want to allow in weight paint mode too
- * so don't be totally strict and just check not-editmode for now
- * XXX We never get here when we are in Weight Paint mode
- */
- if (obedit == NULL) {
- uiItemR(row, &v3dptr, "use_pivot_point_align", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- }
-
/* Transform widget / manipulators */
row = uiLayoutRow(layout, true);
uiItemR(row, &v3dptr, "show_manipulator", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index b11f42bcfef..7a106a27833 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -143,6 +143,8 @@ void draw_motion_paths_cleanup(View3D *v3d);
/* drawobject.c */
void draw_object(Scene *scene, struct ARegion *ar, View3D *v3d, Base *base, const short dflag);
+void draw_object_select(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short dflag);
+
bool draw_glsl_material(Scene *scene, struct Object *ob, View3D *v3d, const char dt);
void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline);
void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob);
@@ -152,7 +154,7 @@ void view3d_cached_text_draw_begin(void);
void view3d_cached_text_draw_add(const float co[3],
const char *str, const size_t str_len,
short xoffs, short flag, const unsigned char col[4]);
-void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, float mat[4][4]);
+void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write);
bool check_object_draw_texture(struct Scene *scene, struct View3D *v3d, const char drawtype);
@@ -195,7 +197,11 @@ void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar);
void view3d_main_region_draw(const struct bContext *C, struct ARegion *ar);
void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride);
void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d);
-void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag);
+void ED_view3d_draw_select_loop(
+ ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar,
+ bool use_obedit_skip, bool use_nearest);
+
+void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag);\
void circf(float x, float y, float rad);
void circ(float x, float y, float rad);
@@ -241,7 +247,7 @@ void ED_view3d_smooth_view_force_finish(
struct bContext *C,
struct View3D *v3d, struct ARegion *ar);
-void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect);
+void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect);
void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d);
void fly_modal_keymap(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index ce4b7f7deeb..ef7b01f7a21 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -119,7 +119,7 @@ void meshobject_foreachScreenVert(
data.clip_flag = clip_flag;
if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
- ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
+ ED_view3d_clipping_local(vc->rv3d, vc->obact->obmat);
}
dm->foreachMappedVert(dm, meshobject_foreachScreenVert__mapFunc, &data, DM_FOREACH_NOP);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index cfeb8af280e..d71639c35d2 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -240,13 +240,23 @@ void view3d_keymap(wmKeyConfig *keyconf)
/* only for region 3D window */
keymap = WM_keymap_find(keyconf, "3D View", SPACE_VIEW3D, 0);
- kmi = WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
+ /* Shift+LMB behavior first, so it has priority over KM_ANY item below. */
+ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "release_confirm", true);
- /*
- * Doesn't work with KM_SHIFT, have to use KM_ANY and filter in invoke
- * */
- // WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
-
+ RNA_boolean_set(kmi->ptr, "use_planar_constraint", true);
+ RNA_boolean_set(kmi->ptr, "use_accurate", false);
+
+ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "release_confirm", true);
+ RNA_boolean_set(kmi->ptr, "use_planar_constraint", false);
+ RNA_boolean_set(kmi->ptr, "use_accurate", true);
+
+ /* Using KM_ANY here to allow holding modifiers before starting to transform. */
+ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
+ RNA_boolean_set(kmi->ptr, "release_confirm", true);
+ RNA_boolean_set(kmi->ptr, "use_planar_constraint", false);
+ RNA_boolean_set(kmi->ptr, "use_accurate", false);
+
WM_keymap_verify_item(keymap, "VIEW3D_OT_cursor3d", ACTIONMOUSE, KM_PRESS, 0, 0);
WM_keymap_verify_item(keymap, "VIEW3D_OT_rotate", MIDDLEMOUSE, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 7448d4c658e..65a6dee2f6c 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -28,6 +28,7 @@
* \ingroup spview3d
*/
+#include "DNA_camera_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
@@ -40,6 +41,7 @@
#include "BLI_math_vector.h"
+#include "BKE_camera.h"
#include "BKE_screen.h"
#include "ED_view3d.h" /* own include */
@@ -462,9 +464,12 @@ bool view3d_get_view_aligned_coordinate(ARegion *ar, float fp[3], const int mval
* \param ar The region (used for the window width and height).
* \param depth_pt The reference location used to calculate the Z depth.
* \param mval The area relative location (such as event->mval converted to floats).
- * \param out The resulting world-space location.
+ * \param r_out The resulting world-space location.
*/
-void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float mval[2], float out[3])
+void ED_view3d_win_to_3d(
+ const View3D *v3d, const ARegion *ar,
+ const float depth_pt[3], const float mval[2],
+ float r_out[3])
{
RegionView3D *rv3d = ar->regiondata;
@@ -488,11 +493,19 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float
else {
float dx = (2.0f * mval[0] / (float)ar->winx) - 1.0f;
float dy = (2.0f * mval[1] / (float)ar->winy) - 1.0f;
+
if (rv3d->persp == RV3D_CAMOB) {
/* ortho camera needs offset applied */
+ const Camera *cam = v3d->camera->data;
+ const int sensor_fit = BKE_camera_sensor_fit(cam->sensor_fit, ar->winx, ar->winy);
const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 4.0f;
- dx += rv3d->camdx * zoomfac;
- dy += rv3d->camdy * zoomfac;
+ const float aspx = ar->winx / (float)ar->winy;
+ const float aspy = ar->winy / (float)ar->winx;
+ const float shiftx = cam->shiftx * 0.5f * (sensor_fit == CAMERA_SENSOR_FIT_HOR ? 1.0f : aspy);
+ const float shifty = cam->shifty * 0.5f * (sensor_fit == CAMERA_SENSOR_FIT_HOR ? aspx : 1.0f);
+
+ dx += (rv3d->camdx + shiftx) * zoomfac;
+ dy += (rv3d->camdy + shifty) * zoomfac;
}
ray_origin[0] = (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
ray_origin[1] = (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
@@ -502,13 +515,16 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float
lambda = ray_point_factor_v3(depth_pt, ray_origin, ray_direction);
}
- madd_v3_v3v3fl(out, ray_origin, ray_direction, lambda);
+ madd_v3_v3v3fl(r_out, ray_origin, ray_direction, lambda);
}
-void ED_view3d_win_to_3d_int(const ARegion *ar, const float depth_pt[3], const int mval[2], float out[3])
+void ED_view3d_win_to_3d_int(
+ const View3D *v3d, const ARegion *ar,
+ const float depth_pt[3], const int mval[2],
+ float r_out[3])
{
const float mval_fl[2] = {mval[0], mval[1]};
- ED_view3d_win_to_3d(ar, depth_pt, mval_fl, out);
+ ED_view3d_win_to_3d(v3d, ar, depth_pt, mval_fl, r_out);
}
/**
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 3c13ab9d595..f2c87953302 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -48,7 +48,6 @@
#include "ED_screen.h"
#include "ED_view3d.h"
-#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "ED_space_api.h"
@@ -280,7 +279,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
}
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,
+ CTX_data_main(C), CTX_data_scene(C), 0,
ruler_info->ar, CTX_wm_view3d(C));
}
else {
@@ -700,7 +699,7 @@ static void view3d_ruler_free(RulerInfo *ruler_info)
static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3],
const int xy[2])
{
- ED_view3d_win_to_3d_int(ruler_info->ar, r_co, xy, r_co);
+ ED_view3d_win_to_3d_int(ruler_info->sa->spacedata.first, ruler_info->ar, r_co, xy, r_co);
}
/* use for mousemove events */
@@ -1009,9 +1008,12 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
case RETKEY:
{
- view3d_ruler_to_gpencil(C, ruler_info);
- do_draw = true;
- exit_code = OPERATOR_FINISHED;
+ /* Enter may be used to invoke from search. */
+ if (event->val == KM_PRESS) {
+ view3d_ruler_to_gpencil(C, ruler_info);
+ do_draw = true;
+ exit_code = OPERATOR_FINISHED;
+ }
break;
}
case DELKEY:
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 3239d07553f..7d927766bbd 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -98,6 +98,8 @@
#include "view3d_intern.h" /* own include */
+// #include "PIL_time_utildefines.h"
+
float ED_view3d_select_dist_px(void)
{
return 75.0f * U.pixelsize;
@@ -1087,7 +1089,9 @@ static void deselectall_except(Scene *scene, Base *b) /* deselect all except b
}
}
-static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], short toggle)
+static Base *object_mouse_select_menu(
+ bContext *C, ViewContext *vc, unsigned int *buffer, int hits,
+ const int mval[2], bool toggle)
{
short baseCount = 0;
bool ok;
@@ -1178,19 +1182,19 @@ static bool selectbuffer_has_bones(const unsigned int *buffer, const unsigned in
}
/* utility function for mixed_bones_object_selectbuffer */
-static short selectbuffer_ret_hits_15(unsigned int *UNUSED(buffer), const short hits15)
+static int selectbuffer_ret_hits_15(unsigned int *UNUSED(buffer), const int hits15)
{
return hits15;
}
-static short selectbuffer_ret_hits_9(unsigned int *buffer, const short hits15, const short hits9)
+static int selectbuffer_ret_hits_9(unsigned int *buffer, const int hits15, const int hits9)
{
const int offs = 4 * hits15;
memcpy(buffer, buffer + offs, 4 * hits9 * sizeof(unsigned int));
return hits9;
}
-static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, const short hits9, const short hits5)
+static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits15, const int hits9, const int hits5)
{
const int offs = 4 * hits15 + 4 * hits9;
memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
@@ -1199,14 +1203,13 @@ static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, c
/* we want a select buffer with bones, if there are... */
/* so check three selection levels and compare */
-static short mixed_bones_object_selectbuffer(
+static int mixed_bones_object_selectbuffer(
ViewContext *vc, unsigned int *buffer, const int mval[2],
bool use_cycle, bool enumerate,
bool *r_do_nearest)
{
rcti rect;
- int offs;
- short hits15, hits9 = 0, hits5 = 0;
+ int hits15, hits9 = 0, hits5 = 0;
bool has_bones15 = false, has_bones9 = false, has_bones5 = false;
static int last_mval[2] = {-100, -100};
bool do_nearest = false;
@@ -1234,44 +1237,57 @@ static short mixed_bones_object_selectbuffer(
do_nearest = do_nearest && !enumerate;
- BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14);
- hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, do_nearest);
+ const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
+ int hits = 0;
+
+ /* we _must_ end cache before return, use 'goto finally' */
+ view3d_opengl_select_cache_begin();
+
+ BLI_rcti_init_pt_radius(&rect, mval, 14);
+ hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
if (hits15 == 1) {
- return selectbuffer_ret_hits_15(buffer, hits15);
+ hits = selectbuffer_ret_hits_15(buffer, hits15);
+ goto finally;
}
else if (hits15 > 0) {
+ int offs;
has_bones15 = selectbuffer_has_bones(buffer, hits15);
offs = 4 * hits15;
- BLI_rcti_init(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9);
- hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
+ BLI_rcti_init_pt_radius(&rect, mval, 9);
+ hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
if (hits9 == 1) {
- return selectbuffer_ret_hits_9(buffer, hits15, hits9);
+ hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
+ goto finally;
}
else if (hits9 > 0) {
has_bones9 = selectbuffer_has_bones(buffer + offs, hits9);
offs += 4 * hits9;
- BLI_rcti_init(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5);
- hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
+ BLI_rcti_init_pt_radius(&rect, mval, 5);
+ hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
if (hits5 == 1) {
- return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
+ hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
+ goto finally;
}
else if (hits5 > 0) {
has_bones5 = selectbuffer_has_bones(buffer + offs, hits5);
}
}
- if (has_bones5) return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
- else if (has_bones9) return selectbuffer_ret_hits_9(buffer, hits15, hits9);
- else if (has_bones15) return selectbuffer_ret_hits_15(buffer, hits15);
-
- if (hits5 > 0) return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
- else if (hits9 > 0) return selectbuffer_ret_hits_9(buffer, hits15, hits9);
- else return selectbuffer_ret_hits_15(buffer, hits15);
+ if (has_bones5) { hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); goto finally; }
+ else if (has_bones9) { hits = selectbuffer_ret_hits_9(buffer, hits15, hits9); goto finally; }
+ else if (has_bones15) { hits = selectbuffer_ret_hits_15(buffer, hits15); goto finally; }
+
+ if (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); goto finally; }
+ else if (hits9 > 0) { hits = selectbuffer_ret_hits_9(buffer, hits15, hits9); goto finally; }
+ else { hits = selectbuffer_ret_hits_15(buffer, hits15); goto finally; }
}
-
- return 0;
+
+finally:
+ view3d_opengl_select_cache_end();
+
+ return hits;
}
/* returns basact */
@@ -1412,7 +1428,7 @@ static bool ed_object_select_pick(
bool is_obedit;
float dist = ED_view3d_select_dist_px() * 1.3333f;
bool retval = false;
- short hits;
+ int hits;
const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
@@ -1464,10 +1480,13 @@ static bool ed_object_select_pick(
unsigned int buffer[MAXPICKBUF];
bool do_nearest;
+ // TIMEIT_START(select_time);
+
/* if objects have posemode set, the bones are in the same selection buffer */
-
hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, true, enumerate, &do_nearest);
-
+
+ // TIMEIT_END(select_time);
+
if (hits > 0) {
/* note: bundles are handling in the same way as bones */
const bool has_bones = selectbuffer_has_bones(buffer, hits);
@@ -1904,9 +1923,9 @@ static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool ext
int a;
unsigned int buffer[MAXPICKBUF];
- short hits;
+ int hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
if (extend == false && select)
BKE_mball_deselect_all(mb);
@@ -1938,9 +1957,9 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
int a;
unsigned int buffer[MAXPICKBUF];
- short hits;
+ int hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
/* clear flag we use to detect point was affected */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next)
@@ -2013,7 +2032,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
int bone_only;
int bone_selected = 0;
int totobj = MAXPICKBUF; /* XXX solve later */
- short hits;
+ int hits;
if ((ob) && (ob->mode & OB_MODE_POSE))
bone_only = 1;
@@ -2037,7 +2056,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
/* selection buffer now has bones potentially too, so we add MAXPICKBUF */
vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(unsigned int), "selection buffer");
- hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, false);
+ hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL);
/*
* LOGIC NOTES (theeth):
* The buffer and ListBase have the same relative order, which makes the selection
@@ -2577,7 +2596,7 @@ static void lattice_circle_select(ViewContext *vc, const bool select, const int
/* NOTE: pose-bone case is copied from editbone case... */
-static short pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, const float screen_co[2])
+static bool pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, const float screen_co[2])
{
CircleSelectUserData *data = userData;
@@ -2655,7 +2674,7 @@ static void pose_circle_select(ViewContext *vc, const bool select, const int mva
}
}
-static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, const float screen_co[2], short head)
+static bool armature_circle_doSelectJoint(void *userData, EditBone *ebone, const float screen_co[2], bool head)
{
CircleSelectUserData *data = userData;
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 8582952d1a0..16b626a5be4 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -54,6 +54,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "UI_resources.h"
+
#include "GPU_select.h"
#include "WM_api.h"
@@ -449,7 +451,7 @@ void ED_view3d_smooth_view_force_finish(
/* force update of view matrix so tools that run immediately after
* can use them without redrawing first */
Scene *scene = CTX_data_scene(C);
- ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL);
+ ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL, NULL);
}
}
@@ -812,19 +814,108 @@ bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb)
return view3d_boundbox_clip_m4(bb, rv3d->persmatob);
}
-float ED_view3d_depth_read_cached(const ViewContext *vc, int x, int y)
+/* -------------------------------------------------------------------- */
+
+/** \name Depth Utilities
+ * \{ */
+
+float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2])
{
ViewDepths *vd = vc->rv3d->depths;
- x -= vc->ar->winrct.xmin;
- y -= vc->ar->winrct.ymin;
+ int x = mval[0];
+ int y = mval[1];
- if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
+ if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) {
return vd->depths[y * vd->w + x];
- else
- return 1;
+ }
+ else {
+ BLI_assert(1.0 <= vd->depth_range[1]);
+ return 1.0f;
+ }
}
+bool ED_view3d_depth_read_cached_normal(
+ const ViewContext *vc, const bglMats *mats, const int mval[2],
+ float r_normal[3])
+{
+ /* Note: we could support passing in a radius.
+ * For now just read 9 pixels. */
+
+ /* pixels surrounding */
+ bool depths_valid[9] = {false};
+ float coords[9][3] = {{0}};
+
+ ARegion *ar = vc->ar;
+ const ViewDepths *depths = vc->rv3d->depths;
+
+ for (int x = 0, i = 0; x < 2; x++) {
+ for (int y = 0; y < 2; y++) {
+ const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
+
+ const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs);
+ if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
+ if (ED_view3d_depth_unproject(ar, mats, mval_ofs, depth, coords[i])) {
+ depths_valid[i] = true;
+ }
+ }
+ i++;
+ }
+ }
+
+ const int edges[2][6][2] = {
+ /* x edges */
+ {{0, 1}, {1, 2},
+ {3, 4}, {4, 5},
+ {6, 7}, {7, 8}},
+ /* y edges */
+ {{0, 3}, {3, 6},
+ {1, 4}, {4, 7},
+ {2, 5}, {5, 8}},
+ };
+
+ float cross[2][3] = {{0.0f}};
+
+ for (int i = 0; i < 6; i++) {
+ for (int axis = 0; axis < 2; axis++) {
+ if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) {
+ float delta[3];
+ sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]);
+ add_v3_v3(cross[axis], delta);
+ }
+ }
+ }
+
+ cross_v3_v3v3(r_normal, cross[0], cross[1]);
+
+ if (normalize_v3(r_normal) != 0.0f) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool ED_view3d_depth_unproject(
+ const ARegion *ar, const bglMats *mats,
+ const int mval[2], const double depth,
+ float r_location_world[3])
+{
+ double p[3];
+ if (gluUnProject(
+ (double)ar->winrct.xmin + mval[0] + 0.5,
+ (double)ar->winrct.ymin + mval[1] + 0.5,
+ depth, mats->modelview, mats->projection, (const GLint *)mats->viewport,
+ &p[0], &p[1], &p[2]))
+ {
+ copy_v3fl_v3db(r_location_world, p);
+ return true;
+ }
+ return false;
+}
+
+/** \} */
+
void ED_view3d_depth_tag_update(RegionView3D *rv3d)
{
if (rv3d->depths)
@@ -908,7 +999,7 @@ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
/**
* \param rect optional for picking (can be NULL).
*/
-void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect)
+void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect)
{
RegionView3D *rv3d = ar->regiondata;
rctf viewplane;
@@ -1091,76 +1182,19 @@ void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d)
}
}
-static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, bool use_obedit_skip)
+/**
+ * Optionally cache data for multiple calls to #view3d_opengl_select
+ *
+ * just avoid GPU_select headers outside this file
+ */
+void view3d_opengl_select_cache_begin(void)
{
- short code = 1;
- char dt;
- short dtx;
-
- if (vc->obedit && vc->obedit->type == OB_MBALL) {
- draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
- }
- else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
- /* if not drawing sketch, draw bones */
- if (!BDR_drawSketchNames(vc)) {
- draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
- }
- }
- else {
- Base *base;
-
- v3d->xray = true; /* otherwise it postpones drawing */
- for (base = scene->base.first; base; base = base->next) {
- if (base->lay & v3d->lay) {
-
- if ((base->object->restrictflag & OB_RESTRICT_SELECT) ||
- (use_obedit_skip && (scene->obedit->data == base->object->data)))
- {
- base->selcol = 0;
- }
- else {
- base->selcol = code;
-
- if (GPU_select_load_id(code)) {
- draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR);
-
- /* we draw duplicators for selection too */
- if ((base->object->transflag & OB_DUPLI)) {
- ListBase *lb;
- DupliObject *dob;
- Base tbase;
-
- tbase.flag = OB_FROMDUPLI;
- lb = object_duplilist(G.main->eval_ctx, scene, base->object);
-
- for (dob = lb->first; dob; dob = dob->next) {
- float omat[4][4];
-
- tbase.object = dob->ob;
- copy_m4_m4(omat, dob->ob->obmat);
- copy_m4_m4(dob->ob->obmat, dob->mat);
-
- /* extra service: draw the duplicator in drawtype of parent */
- /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
- dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
- dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
-
- draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR);
-
- tbase.object->dt = dt;
- tbase.object->dtx = dtx;
+ GPU_select_cache_begin();
+}
- copy_m4_m4(dob->ob->obmat, omat);
- }
- free_object_duplilist(lb);
- }
- }
- code++;
- }
- }
- }
- v3d->xray = false; /* restore */
- }
+void view3d_opengl_select_cache_end(void)
+{
+ GPU_select_cache_end();
}
/**
@@ -1170,32 +1204,74 @@ static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegi
*
* \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
*/
-short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, bool do_nearest)
+int view3d_opengl_select(
+ ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input,
+ eV3DSelectMode select_mode)
{
+ struct bThemeState theme_state;
Scene *scene = vc->scene;
View3D *v3d = vc->v3d;
ARegion *ar = vc->ar;
- rctf rect;
- short hits;
+ rcti rect;
+ int hits;
const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL);
- const bool do_passes = do_nearest && GPU_select_query_check_active();
+ const bool is_pick_select = (U.gpu_select_pick_deph != 0);
+ const bool do_passes = (
+ (is_pick_select == false) &&
+ (select_mode == VIEW3D_SELECT_PICK_NEAREST) &&
+ GPU_select_query_check_active());
+ const bool use_nearest = (is_pick_select && select_mode == VIEW3D_SELECT_PICK_NEAREST);
+
+ char gpu_select_mode;
- G.f |= G_PICKSEL;
-
/* case not a border select */
if (input->xmin == input->xmax) {
- rect.xmin = input->xmin - 12; /* seems to be default value for bones only now */
- rect.xmax = input->xmin + 12;
- rect.ymin = input->ymin - 12;
- rect.ymax = input->ymin + 12;
+ /* seems to be default value for bones only now */
+ BLI_rcti_init_pt_radius(&rect, (const int[2]){input->xmin, input->ymin}, 12);
}
else {
- BLI_rctf_rcti_copy(&rect, input);
+ rect = *input;
}
-
- view3d_winmatrix_set(ar, v3d, &rect);
- mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
-
+
+ if (is_pick_select) {
+ if (is_pick_select && select_mode == VIEW3D_SELECT_PICK_NEAREST) {
+ gpu_select_mode = GPU_SELECT_PICK_NEAREST;
+ }
+ else if (is_pick_select && select_mode == VIEW3D_SELECT_PICK_ALL) {
+ gpu_select_mode = GPU_SELECT_PICK_ALL;
+ }
+ else {
+ gpu_select_mode = GPU_SELECT_ALL;
+ }
+ }
+ else {
+ if (do_passes) {
+ gpu_select_mode = GPU_SELECT_NEAREST_FIRST_PASS;
+ }
+ else {
+ gpu_select_mode = GPU_SELECT_ALL;
+ }
+ }
+
+ /* Tools may request depth outside of regular drawing code. */
+ UI_Theme_Store(&theme_state);
+ UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
+
+ /* Re-use cache (rect must be smaller then the cached)
+ * other context is assumed to be unchanged */
+ if (GPU_select_is_cached()) {
+ GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
+ GPU_select_cache_load_id();
+ hits = GPU_select_end();
+ goto finally;
+ }
+
+ G.f |= G_PICKSEL;
+
+ /* Important we use the 'viewmat' and don't re-calculate since
+ * the object & bone view locking takes 'rect' into account, see: T51629. */
+ ED_view3d_draw_setup_view(vc->win, scene, ar, v3d, vc->rv3d->viewmat, NULL, &rect);
+
if (v3d->drawtype > OB_WIRE) {
v3d->zbuf = true;
glEnable(GL_DEPTH_TEST);
@@ -1204,27 +1280,23 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_set(vc->rv3d);
- if (do_passes)
- GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
- else
- GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_ALL, 0);
+ GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
- view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);
+ ED_view3d_draw_select_loop(vc, scene, v3d, ar, use_obedit_skip, use_nearest);
hits = GPU_select_end();
/* second pass, to get the closest object to camera */
- if (do_passes) {
+ if (do_passes && (hits > 0)) {
GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
- view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);
+ ED_view3d_draw_select_loop(vc, scene, v3d, ar, use_obedit_skip, use_nearest);
GPU_select_end();
}
G.f &= ~G_PICKSEL;
- view3d_winmatrix_set(ar, v3d, NULL);
- mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
+ ED_view3d_draw_setup_view(vc->win, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL);
if (v3d->drawtype > OB_WIRE) {
v3d->zbuf = 0;
@@ -1233,9 +1305,12 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_disable();
-
+
+finally:
if (hits < 0) printf("Too many objects in select buffer\n"); /* XXX make error message */
+ UI_Theme_Restore(&theme_state);
+
return hits;
}
@@ -1428,6 +1503,8 @@ static bool view3d_localview_init(
}
}
+ DAG_on_visible_update(bmain, false);
+
return ok;
}
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 17c08ed4205..5248a260617 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -49,7 +49,6 @@
#include "ED_screen.h"
#include "ED_space_api.h"
-#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "PIL_time.h" /* smoothview */
@@ -588,7 +587,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->rflag |= RV3D_NAVIGATING;
walk->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), walk->scene, SNAP_OBJECT_USE_CACHE,
+ CTX_data_main(C), walk->scene, 0,
walk->ar, walk->v3d);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
@@ -674,16 +673,6 @@ static int walkEnd(bContext *C, WalkInfo *walk)
return OPERATOR_CANCELLED;
}
-static bool wm_event_is_last_mousemove(const wmEvent *event)
-{
- while ((event = event->next)) {
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
- return false;
- }
- }
- return true;
-}
-
static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent *event)
{
if (event->type == TIMER && event->customdata == walk->timer) {
@@ -736,7 +725,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
}
else
#endif
- if (wm_event_is_last_mousemove(event)) {
+ if (WM_event_is_last_mousemove(event)) {
wmWindow *win = CTX_wm_window(C);
#ifdef __APPLE__
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index daf0aed59e7..c2f04005e83 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -51,7 +51,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_ghash.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BLI_memarena.h"
#include "BKE_nla.h"
@@ -103,7 +103,7 @@ static void drawEdgeSlide(TransInfo *t);
static void drawVertSlide(TransInfo *t);
static void postInputRotation(TransInfo *t, float values[3]);
-static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around);
+static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around);
static void initSnapSpatial(TransInfo *t, float r_snap[3]);
@@ -1605,7 +1605,7 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size)
offset = -offset;
length = -length;
size = -size;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case RIGHT:
glBegin(GL_LINES);
glVertex2s(offset, 0);
@@ -1621,7 +1621,7 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size)
offset = -offset;
length = -length;
size = -size;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case UP:
glBegin(GL_LINES);
glVertex2s(0, offset);
@@ -1640,7 +1640,7 @@ static void drawArrowHead(ArrowDirection d, short size)
switch (d) {
case LEFT:
size = -size;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case RIGHT:
glBegin(GL_LINES);
glVertex2s(0, 0);
@@ -1652,7 +1652,7 @@ static void drawArrowHead(ArrowDirection d, short size)
case DOWN:
size = -size;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case UP:
glBegin(GL_LINES);
glVertex2s(0, 0);
@@ -2176,7 +2176,14 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
calculateCenter(t);
if (event) {
- initMouseInput(t, &t->mouse, t->center2d, event->mval);
+ /* Initialize accurate transform to settings requested by keymap. */
+ bool use_accurate = false;
+ if ((prop = RNA_struct_find_property(op->ptr, "use_accurate")) && RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
+ use_accurate = true;
+ }
+ }
+ initMouseInput(t, &t->mouse, t->center2d, event->mval, use_accurate);
}
switch (mode) {
@@ -2871,7 +2878,9 @@ static void initBend(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
- calculateCenterCursor(t, t->center);
+ if ((t->flag & T_OVERRIDE_CENTER) == 0) {
+ calculateCenterCursor(t, t->center);
+ }
calculateCenterGlobal(t, t->center, t->center_global);
t->val = 0.0f;
@@ -2880,7 +2889,7 @@ static void initBend(TransInfo *t)
curs = ED_view3d_cursor3d_get(t->scene, t->view);
copy_v3_v3(data->warp_sta, curs);
- ED_view3d_win_to_3d(t->ar, curs, mval_fl, data->warp_end);
+ ED_view3d_win_to_3d(t->sa->spacedata.first, t->ar, curs, mval_fl, data->warp_end);
copy_v3_v3(data->warp_nor, t->viewinv[2]);
if (t->flag & T_EDIT) {
@@ -3044,19 +3053,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
/** \name Transform Shear
* \{ */
-static void postInputShear(TransInfo *UNUSED(t), float values[3])
-{
- mul_v3_fl(values, 0.05f);
-}
-
static void initShear(TransInfo *t)
{
t->mode = TFM_SHEAR;
t->transform = applyShear;
t->handleEvent = handleEventShear;
-
- setInputPostFct(&t->mouse, postInputShear);
- initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
+
+ initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
t->idx_max = 0;
t->num.idx_max = 0;
@@ -3078,24 +3081,24 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
/* Use custom.mode.data pointer to signal Shear direction */
if (t->custom.mode.data == NULL) {
- initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
+ initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_RATIO);
t->custom.mode.data = (void *)1;
}
else {
- initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
+ initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
t->custom.mode.data = NULL;
}
status = TREDRAW_HARD;
}
else if (event->type == XKEY && event->val == KM_PRESS) {
- initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
+ initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
t->custom.mode.data = NULL;
status = TREDRAW_HARD;
}
else if (event->type == YKEY && event->val == KM_PRESS) {
- initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
+ initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_RATIO);
t->custom.mode.data = (void *)1;
status = TREDRAW_HARD;
@@ -3722,6 +3725,12 @@ static void initRotation(TransInfo *t)
copy_v3_v3(t->axis_orig, t->axis);
}
+/**
+ * Applies values of rotation to `td->loc` and `td->ext->quat`
+ * based on a rotation matrix (mat) and a pivot (center).
+ *
+ * Protected axis and other transform settings are taken into account.
+ */
static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], const float *center)
{
float vec[3], totmat[3][3], smat[3][3];
@@ -4060,13 +4069,15 @@ static void initTrackball(TransInfo *t)
static void applyTrackballValue(TransInfo *t, const float axis1[3], const float axis2[3], float angles[2])
{
TransData *td = t->data;
- float mat[3][3], smat[3][3], totmat[3][3];
+ float mat[3][3];
+ float axis[3];
+ float angle;
int i;
- axis_angle_normalized_to_mat3(smat, axis1, angles[0]);
- axis_angle_normalized_to_mat3(totmat, axis2, angles[1]);
-
- mul_m3_m3m3(mat, smat, totmat);
+ mul_v3_v3fl(axis, axis1, angles[0]);
+ madd_v3_v3fl(axis, axis2, angles[1]);
+ angle = normalize_v3(axis);
+ axis_angle_normalized_to_mat3(mat, axis, angle);
for (i = 0; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
@@ -4076,10 +4087,7 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float
continue;
if (t->flag & T_PROP_EDIT) {
- axis_angle_normalized_to_mat3(smat, axis1, td->factor * angles[0]);
- axis_angle_normalized_to_mat3(totmat, axis2, td->factor * angles[1]);
-
- mul_m3_m3m3(mat, smat, totmat);
+ axis_angle_normalized_to_mat3(mat, axis, td->factor * angle);
}
ElementRotation(t, td, mat, t->around);
@@ -4265,7 +4273,7 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
bUnit_AsString(distvec, sizeof(distvec), dist * t->scene->unit.scale_length, 4, t->scene->unit.system,
B_UNIT_LENGTH, do_split, false);
}
- else if (dist > 1e10f || dist < -1e10f) {
+ else if (dist > 1e10f || dist < -1e10f) {
/* prevent string buffer overflow */
BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist);
}
@@ -4339,9 +4347,22 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
{
TransData *td = t->data;
float tvec[3];
- int i;
- for (i = 0; i < t->total; i++, td++) {
+ /* The ideal would be "apply_snap_align_rotation" only when a snap point is found
+ * so, maybe inside this function is not the best place to apply this rotation.
+ * but you need "handle snapping rotation before doing the translation" (really?) */
+ const bool apply_snap_align_rotation = usingSnappingNormal(t);// && (t->tsnap.status & POINT_INIT);
+ float pivot[3];
+ if (apply_snap_align_rotation) {
+ copy_v3_v3(pivot, t->tsnap.snapTarget);
+ /* The pivot has to be in local-space (see T49494) */
+ if (t->flag & (T_EDIT | T_POSE)) {
+ Object *ob = t->obedit ? t->obedit : t->poseobj;
+ mul_m4_v3(ob->imat, pivot);
+ }
+ }
+
+ for (int i = 0; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -4352,7 +4373,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
bool use_rotate_offset = false;
/* handle snapping rotation before doing the translation */
- if (usingSnappingNormal(t)) {
+ if (apply_snap_align_rotation) {
float mat[3][3];
if (validSnappingNormal(t)) {
@@ -4370,7 +4391,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
unit_m3(mat);
}
- ElementRotation_ex(t, td, mat, t->tsnap.snapTarget);
+ ElementRotation_ex(t, td, mat, pivot);
if (td->loc) {
use_rotate_offset = true;
@@ -4922,7 +4943,7 @@ static void initPushPull(TransInfo *t)
static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
{
- float vec[3], axis[3];
+ float vec[3], axis_global[3];
float distance;
int i;
char str[UI_MAX_DRAW_STR];
@@ -4950,7 +4971,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
}
if (t->con.applyRot && t->con.mode & CON_APPLY) {
- t->con.applyRot(t, NULL, axis, NULL);
+ t->con.applyRot(t, NULL, axis_global, NULL);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4962,7 +4983,11 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
sub_v3_v3v3(vec, t->center, td->center);
if (t->con.applyRot && t->con.mode & CON_APPLY) {
+ float axis[3];
+ copy_v3_v3(axis, axis_global);
t->con.applyRot(t, td, axis, NULL);
+
+ mul_m3_v3(td->smtx, axis);
if (isLockConstraint(t)) {
float dvec[3];
project_v3_v3v3(dvec, vec, axis);
@@ -5535,7 +5560,7 @@ static void slide_origdata_interp_data_vert(
float v_proj[3][3];
if (do_loop_weight || do_loop_mdisps) {
- project_plane_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis);
+ project_plane_normalized_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis);
}
// BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) {
@@ -5569,19 +5594,19 @@ static void slide_origdata_interp_data_vert(
/* In the unlikely case that we're next to a zero length edge - walk around the to the next.
* Since we only need to check if the vertex is in this corner,
* its not important _which_ loop - as long as its not overlapping 'sv->co_orig_3d', see: T45096. */
- project_plane_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) &&
((l_prev = l_prev->prev) != l->next)))
{
co_prev = slide_origdata_orig_vert_co(sod, l_prev->v);
- project_plane_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
}
- project_plane_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) &&
((l_next = l_next->next) != l->prev)))
{
co_next = slide_origdata_orig_vert_co(sod, l_next->v);
- project_plane_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
}
if (co_prev_ok && co_next_ok) {
@@ -8337,8 +8362,15 @@ static void initTimeSlide(TransInfo *t)
TransData *td = t->data;
for (i = 0; i < t->total; i++, td++) {
- if (min > *(td->val)) min = *(td->val);
- if (max < *(td->val)) max = *(td->val);
+ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+ float val = *(td->val);
+
+ /* strip/action time to global (mapped) time */
+ if (adt)
+ val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP);
+
+ if (min > val) min = val;
+ if (max < val) max = val;
}
if (min == max) {
@@ -8413,25 +8445,38 @@ static void applyTimeSlideValue(TransInfo *t, float sval)
*/
AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
float cval = t->values[0];
-
- /* apply NLA-mapping to necessary values */
- if (adt)
- cval = BKE_nla_tweakedit_remap(adt, cval, NLATIME_CONVERT_UNMAP);
-
+
/* only apply to data if in range */
if ((sval > minx) && (sval < maxx)) {
float cvalc = CLAMPIS(cval, minx, maxx);
+ float ival = td->ival;
float timefac;
-
+
+ /* NLA mapping magic here works as follows:
+ * - "ival" goes from strip time to global time
+ * - calculation is performed into td->val in global time
+ * (since sval and min/max are all in global time)
+ * - "td->val" then gets put back into strip time
+ */
+ if (adt) {
+ /* strip to global */
+ ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP);
+ }
+
/* left half? */
- if (td->ival < sval) {
- timefac = (sval - td->ival) / (sval - minx);
+ if (ival < sval) {
+ timefac = (sval - ival) / (sval - minx);
*(td->val) = cvalc - timefac * (cvalc - minx);
}
else {
- timefac = (td->ival - sval) / (maxx - sval);
+ timefac = (ival - sval) / (maxx - sval);
*(td->val) = cvalc + timefac * (maxx - cvalc);
}
+
+ if (adt) {
+ /* global to strip */
+ *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP);
+ }
}
}
}
@@ -8490,12 +8535,14 @@ static void initTimeScale(TransInfo *t)
/* recalculate center2d to use CFRA and mouse Y, since that's
* what is used in time scale */
- t->center[0] = t->scene->r.cfra;
- projectFloatView(t, t->center, center);
- center[1] = t->mouse.imval[1];
+ if ((t->flag & T_OVERRIDE_CENTER) == 0) {
+ t->center[0] = t->scene->r.cfra;
+ projectFloatView(t, t->center, center);
+ center[1] = t->mouse.imval[1];
+ }
/* force a reinit with the center2d used here */
- initMouseInput(t, &t->mouse, center, t->mouse.imval);
+ initMouseInput(t, &t->mouse, center, t->mouse.imval, false);
initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index a59f9dc43dd..06a60456cdb 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -84,8 +84,8 @@ typedef struct TransSnap {
bool peel;
bool snap_spatial_grid;
short status;
- float snapPoint[3]; /* snapping from this point */
- float snapTarget[3]; /* to this point */
+ float snapPoint[3]; /* snapping from this point (in global-space)*/
+ float snapTarget[3]; /* to this point (in global-space)*/
float snapNormal[3];
char snapNodeBorder;
ListBase points;
@@ -533,6 +533,9 @@ typedef struct TransInfo {
/* alternative transformation. used to add offset to tracking markers */
#define T_ALT_TRANSFORM (1 << 24)
+ /** #TransInfo.center has been set, don't change it. */
+#define T_OVERRIDE_CENTER (1 << 25)
+
/* TransInfo->modifiers */
#define MOD_CONSTRAINT_SELECT 0x01
#define MOD_PRECISION 0x02
@@ -728,7 +731,7 @@ typedef enum {
INPUT_CUSTOM_RATIO_FLIP,
} MouseInputMode;
-void initMouseInput(TransInfo *t, MouseInput *mi, const float center[2], const int mval[2]);
+void initMouseInput(TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], const bool precision);
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode);
eRedrawFlag handleMouseInput(struct TransInfo *t, struct MouseInput *mi, const struct wmEvent *event);
void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, const int mval[2], float output[3]);
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index d7b670b6476..5621eede543 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -831,6 +831,13 @@ static void drawObjectConstraint(TransInfo *t)
}
}
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* only draw a constraint line for one point, otherwise we can't see anything */
+ if ((options & DRAWLIGHT) == 0) {
+ break;
+ }
+ }
+
if (t->flag & T_OBJECT) {
copy_v3_v3(co, td->ob->obmat[3]);
axismtx = td->axismtx;
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index ce3d903b8f6..9d63afeb85c 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -771,29 +771,37 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
/* -------- Auto-IK ---------- */
/* adjust pose-channel's auto-ik chainlen */
-static void pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
+static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
{
bConstraint *con;
+ bool changed = false;
/* don't bother to search if no valid constraints */
- if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0)
- return;
+ if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0) {
+ return changed;
+ }
/* check if pchan has ik-constraint */
for (con = pchan->constraints.first; con; con = con->next) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
bKinematicConstraint *data = con->data;
-
+
/* only accept if a temporary one (for auto-ik) */
if (data->flag & CONSTRAINT_IK_TEMP) {
/* chainlen is new chainlen, but is limited by maximum chainlen */
- if ((chainlen == 0) || (chainlen > data->max_rootbone))
+ const int old_rootbone = data->rootbone;
+ if ((chainlen == 0) || (chainlen > data->max_rootbone)) {
data->rootbone = data->max_rootbone;
- else
+ }
+ else {
data->rootbone = chainlen;
+ }
+ changed |= (data->rootbone != old_rootbone);
}
}
}
+
+ return changed;
}
/* change the chain-length of auto-ik */
@@ -809,7 +817,13 @@ void transform_autoik_update(TransInfo *t, short mode)
}
else if (mode == -1) {
/* mode==-1 is from WHEELMOUSEUP... decreases len */
- if (*chainlen > 0) (*chainlen)--;
+ if (*chainlen > 0) {
+ (*chainlen)--;
+ }
+ else {
+ /* IK length did not change, skip updates. */
+ return;
+ }
}
/* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
@@ -817,8 +831,19 @@ void transform_autoik_update(TransInfo *t, short mode)
return;
/* apply to all pose-channels */
+ bool changed = false;
for (pchan = t->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
- pchan_autoik_adjust(pchan, *chainlen);
+ changed |= pchan_autoik_adjust(pchan, *chainlen);
+ }
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!DEG_depsgraph_use_legacy())
+#endif
+ {
+ if (changed) {
+ /* TODO(sergey): Consider doing partial update only. */
+ DAG_relations_tag_update(G.main);
+ }
}
}
@@ -828,7 +853,9 @@ static void pose_grab_with_ik_clear(Object *ob)
bKinematicConstraint *data;
bPoseChannel *pchan;
bConstraint *con, *next;
+#ifdef WITH_LEGACY_DEPSGRAPH
bool need_dependency_update = false;
+#endif
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* clear all temporary lock flags */
@@ -843,7 +870,9 @@ static void pose_grab_with_ik_clear(Object *ob)
data = con->data;
if (data->flag & CONSTRAINT_IK_TEMP) {
/* iTaSC needs clear for removed constraints */
+#ifdef WITH_LEGACY_DEPSGRAPH
need_dependency_update = true;
+#endif
BIK_clear_data(ob->pose);
BLI_remlink(&pchan->constraints, con);
@@ -1496,6 +1525,48 @@ static TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struc
return hdata;
}
+/**
+ * For the purpose of transform code we need to behave as if handles are selected,
+ * even when they aren't (see special case below).
+ */
+static int bezt_select_to_transform_triple_flag(
+ const BezTriple *bezt, const bool hide_handles)
+{
+ int flag = 0;
+
+ if (hide_handles) {
+ if (bezt->f2 & SELECT) {
+ flag = (1 << 0) | (1 << 1) | (1 << 2);
+ }
+ }
+ else {
+ flag = (
+ ((bezt->f1 & SELECT) ? (1 << 0) : 0) |
+ ((bezt->f2 & SELECT) ? (1 << 1) : 0) |
+ ((bezt->f3 & SELECT) ? (1 << 2) : 0)
+ );
+ }
+
+ /* Special case for auto & aligned handles:
+ * When a center point is being moved without the handles,
+ * leaving the handles stationary makes no sense and only causes strange behavior,
+ * where one handle is arbitrarily anchored, the other one is aligned and lengthened
+ * based on where the center point is moved. Also a bug when cancelling, see: T52007.
+ *
+ * A more 'correct' solution could be to store handle locations in 'TransDataCurveHandleFlags'.
+ * However that doesn't resolve odd behavior, so best transform the handles in this case.
+ */
+ if ((flag != ((1 << 0) | (1 << 1) | (1 << 2))) && (flag & (1 << 1))) {
+ if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) &&
+ ELEM(bezt->h2, HD_AUTO, HD_ALIGN))
+ {
+ flag = (1 << 0) | (1 << 1) | (1 << 2);
+ }
+ }
+
+ return flag;
+}
+
static void createTransCurveVerts(TransInfo *t)
{
Curve *cu = t->obedit->data;
@@ -1513,22 +1584,22 @@ static void createTransCurveVerts(TransInfo *t)
/* to be sure */
if (cu->editnurb == NULL) return;
+#define SEL_F1 (1 << 0)
+#define SEL_F2 (1 << 1)
+#define SEL_F3 (1 << 2)
+
/* count total of vertices, check identical as in 2nd loop for making transdata! */
nurbs = BKE_curve_editNurbs_get(cu);
for (nu = nurbs->first; nu; nu = nu->next) {
if (nu->type == CU_BEZIER) {
for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
if (bezt->hide == 0) {
- if (hide_handles) {
- if (bezt->f2 & SELECT) countsel += 3;
- if (is_prop_edit) count += 3;
- }
- else {
- if (bezt->f1 & SELECT) countsel++;
- if (bezt->f2 & SELECT) countsel++;
- if (bezt->f3 & SELECT) countsel++;
- if (is_prop_edit) count += 3;
- }
+ const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+ if (bezt_tx & SEL_F1) { countsel++; }
+ if (bezt_tx & SEL_F2) { countsel++; }
+ if (bezt_tx & SEL_F3) { countsel++; }
+ if (is_prop_edit) count += 3;
+
}
}
}
@@ -1579,10 +1650,10 @@ static void createTransCurveVerts(TransInfo *t)
}
}
- if (is_prop_edit ||
- ((bezt->f2 & SELECT) && hide_handles) ||
- ((bezt->f1 & SELECT) && hide_handles == 0))
- {
+ /* Elements that will be transform (not always a match to selection). */
+ const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+
+ if (is_prop_edit || bezt_tx & SEL_F1) {
copy_v3_v3(td->iloc, bezt->vec[0]);
td->loc = bezt->vec[0];
copy_v3_v3(td->center, bezt->vec[(hide_handles ||
@@ -1613,7 +1684,7 @@ static void createTransCurveVerts(TransInfo *t)
}
/* This is the Curve Point, the other two are handles */
- if (is_prop_edit || (bezt->f2 & SELECT)) {
+ if (is_prop_edit || bezt_tx & SEL_F2) {
copy_v3_v3(td->iloc, bezt->vec[1]);
td->loc = bezt->vec[1];
copy_v3_v3(td->center, td->loc);
@@ -1639,7 +1710,7 @@ static void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->axismtx, axismtx);
}
- if ((bezt->f1 & SELECT) == 0 && (bezt->f3 & SELECT) == 0)
+ if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0)
/* If the middle is selected but the sides arnt, this is needed */
if (hdata == NULL) { /* if the handle was not saved by the previous handle */
hdata = initTransDataCurveHandles(td, bezt);
@@ -1649,10 +1720,7 @@ static void createTransCurveVerts(TransInfo *t)
count++;
tail++;
}
- if (is_prop_edit ||
- ((bezt->f2 & SELECT) && hide_handles) ||
- ((bezt->f3 & SELECT) && hide_handles == 0))
- {
+ if (is_prop_edit || bezt_tx & SEL_F3) {
copy_v3_v3(td->iloc, bezt->vec[2]);
td->loc = bezt->vec[2];
copy_v3_v3(td->center, bezt->vec[(hide_handles ||
@@ -1707,6 +1775,26 @@ static void createTransCurveVerts(TransInfo *t)
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
if (is_prop_edit || (bp->f1 & SELECT)) {
+ float axismtx[3][3];
+
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ if (nu->pntsv == 1) {
+ float normal[3], plane[3];
+
+ BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+ BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+
+ if (createSpaceNormalTangent(axismtx, normal, plane)) {
+ /* pass */
+ }
+ else {
+ normalize_v3(normal);
+ axis_dominant_v3_to_m3(axismtx, normal);
+ invert_m3(axismtx);
+ }
+ }
+ }
+
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
copy_v3_v3(td->center, td->loc);
@@ -1725,6 +1813,11 @@ static void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ if (nu->pntsv == 1) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
+ }
td++;
count++;
@@ -1740,6 +1833,10 @@ static void createTransCurveVerts(TransInfo *t)
calc_distanceCurveVerts(head, tail - 1);
}
}
+
+#undef SEL_F1
+#undef SEL_F2
+#undef SEL_F3
}
/* ********************* lattice *************** */
@@ -1973,9 +2070,12 @@ void flushTransParticles(TransInfo *t)
/* ********************* mesh ****************** */
-static bool bmesh_test_dist_add(BMVert *v, BMVert *v_other,
- float *dists, const float *dists_prev,
- float mtx[3][3])
+static bool bmesh_test_dist_add(
+ BMVert *v, BMVert *v_other,
+ float *dists, const float *dists_prev,
+ /* optionally track original index */
+ int *index, const int *index_prev,
+ float mtx[3][3])
{
if ((BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) &&
(BM_elem_flag_test(v_other, BM_ELEM_HIDDEN) == 0))
@@ -1990,6 +2090,9 @@ static bool bmesh_test_dist_add(BMVert *v, BMVert *v_other,
dist_other = dists_prev[i] + len_v3(vec);
if (dist_other < dists[i_other]) {
dists[i_other] = dist_other;
+ if (index != NULL) {
+ index[i_other] = index_prev[i];
+ }
return true;
}
}
@@ -1997,11 +2100,13 @@ static bool bmesh_test_dist_add(BMVert *v, BMVert *v_other,
return false;
}
-static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float *dists)
+/**
+ * \param mtx: Measure disatnce in this space.
+ * \param dists: Store the closest connected distance to selected vertices.
+ * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
+ */
+static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float *dists, int *index)
{
- /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */
- float *dists_prev = MEM_mallocN(bm->totvert * sizeof(float), __func__);
-
BLI_LINKSTACK_DECLARE(queue, BMVert *);
/* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */
@@ -2022,17 +2127,27 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
dist = FLT_MAX;
+ if (index != NULL) {
+ index[i] = i;
+ }
}
else {
BLI_LINKSTACK_PUSH(queue, v);
dist = 0.0f;
+ if (index != NULL) {
+ index[i] = i;
+ }
}
- dists[i] = dists_prev[i] = dist;
+ dists[i] = dist;
}
bm->elem_index_dirty &= ~BM_VERT;
}
+ /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */
+ float *dists_prev = MEM_dupallocN(dists);
+ int *index_prev = MEM_dupallocN(index); /* may be NULL */
+
do {
BMVert *v;
LinkNode *lnk;
@@ -2061,7 +2176,7 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
/* edge distance */
{
BMVert *v_other = BM_edge_other_vert(e_iter, v);
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
BM_elem_flag_enable(v_other, BM_ELEM_TAG);
BLI_LINKSTACK_PUSH(queue_next, v_other);
@@ -2086,7 +2201,7 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
(BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0))
{
BMVert *v_other = l_iter_radial->next->next->v;
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
BM_elem_flag_enable(v_other, BM_ELEM_TAG);
BLI_LINKSTACK_PUSH(queue_next, v_other);
@@ -2110,6 +2225,9 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
/* keep in sync, avoid having to do full memcpy each iteration */
dists_prev[i] = dists[i];
+ if (index != NULL) {
+ index_prev[i] = index[i];
+ }
}
BLI_LINKSTACK_SWAP(queue, queue_next);
@@ -2123,9 +2241,14 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
BLI_LINKSTACK_FREE(queue_next);
MEM_freeN(dists_prev);
+ if (index_prev != NULL) {
+ MEM_freeN(index_prev);
+ }
}
-static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, int *r_island_tot, int **r_island_vert_map)
+static struct TransIslandData *editmesh_islands_info_calc(
+ BMEditMesh *em, int *r_island_tot, int **r_island_vert_map,
+ bool calc_single_islands)
{
BMesh *bm = em->bm;
struct TransIslandData *trans_islands;
@@ -2237,6 +2360,42 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, int *r
MEM_freeN(groups_array);
MEM_freeN(group_index);
+ /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */
+ if (calc_single_islands) {
+ BMIter viter;
+ BMVert *v;
+ int group_tot_single = 0;
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
+ group_tot_single += 1;
+ }
+ }
+
+ if (group_tot_single != 0) {
+ trans_islands = MEM_reallocN(trans_islands, sizeof(*trans_islands) * (group_tot + group_tot_single));
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
+ struct TransIslandData *v_island = &trans_islands[group_tot];
+ vert_map[i] = group_tot;
+
+ copy_v3_v3(v_island->co, v->co);
+
+ if (is_zero_v3(v->no) != 0.0f) {
+ axis_dominant_v3_to_m3(v_island->axismtx, v->no);
+ invert_m3(v_island->axismtx);
+ }
+ else {
+ unit_m3(v_island->axismtx);
+ }
+
+ group_tot += 1;
+ }
+ }
+ }
+ }
+
*r_island_tot = group_tot;
*r_island_vert_map = vert_map;
@@ -2336,6 +2495,12 @@ static void createTransEditVerts(TransInfo *t)
int island_info_tot;
int *island_vert_map = NULL;
+ /* Even for translation this is needed because of island-orientation, see: T51651. */
+ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
+ /* Original index of our connected vertex when connected distances are calculated.
+ * Optional, allocate if needed. */
+ int *dists_index = NULL;
+
if (t->flag & T_MIRROR) {
EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology);
mirror = 1;
@@ -2367,8 +2532,12 @@ static void createTransEditVerts(TransInfo *t)
t->total = count;
/* allocating scratch arrays */
- if (prop_mode & T_PROP_CONNECTED)
- dists = MEM_mallocN(em->bm->totvert * sizeof(float), "scratch nears");
+ if (prop_mode & T_PROP_CONNECTED) {
+ dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__);
+ if (is_island_center) {
+ dists_index = MEM_mallocN(em->bm->totvert * sizeof(int), __func__);
+ }
+ }
}
else {
t->total = bm->totvertsel;
@@ -2390,11 +2559,17 @@ static void createTransEditVerts(TransInfo *t)
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
if (prop_mode & T_PROP_CONNECTED) {
- editmesh_set_connectivity_distance(em->bm, mtx, dists);
+ editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index);
}
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map);
+ if (is_island_center) {
+ /* In this specific case, near-by vertices will need to know the island of the nearest connected vertex. */
+ const bool calc_single_islands = (
+ (prop_mode & T_PROP_CONNECTED) &&
+ (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (em->selectmode & SCE_SELECT_VERTEX));
+
+ island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map, calc_single_islands);
}
/* detect CrazySpace [tm] */
@@ -2444,10 +2619,16 @@ static void createTransEditVerts(TransInfo *t)
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- struct TransIslandData *v_island = (island_info && island_vert_map[a] != -1) ?
- &island_info[island_vert_map[a]] : NULL;
+ struct TransIslandData *v_island = NULL;
float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : NULL;
+ if (island_info) {
+ const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
+ v_island = (island_vert_map[connected_index] != -1) ?
+ &island_info[island_vert_map[connected_index]] : NULL;
+ }
+
+
VertsToTransData(t, tob, tx, em, eve, bweight, v_island);
if (tx)
tx++;
@@ -2526,6 +2707,8 @@ cleanup:
MEM_freeN(defmats);
if (dists)
MEM_freeN(dists);
+ if (dists_index)
+ MEM_freeN(dists_index);
if (t->flag & T_MIRROR) {
EDBM_verts_mirror_cache_end(em);
@@ -2618,7 +2801,7 @@ void flushTransSeq(TransInfo *t)
tdsq = (TransDataSeq *)td->extra;
seq = tdsq->seq;
old_start = seq->start;
- new_frame = iroundf(td2d->loc[0]);
+ new_frame = round_fl_to_int(td2d->loc[0]);
switch (tdsq->sel_flag) {
case SELECT:
@@ -2630,7 +2813,7 @@ void flushTransSeq(TransInfo *t)
seq->start = new_frame - tdsq->start_offset;
#endif
if (seq->depth == 0) {
- seq->machine = iroundf(td2d->loc[1]);
+ seq->machine = round_fl_to_int(td2d->loc[1]);
CLAMP(seq->machine, 1, MAXSEQ);
}
break;
@@ -3578,7 +3761,7 @@ void flushTransIntFrameActionData(TransInfo *t)
/* flush data! */
for (i = 0; i < t->total; i++, tfd++) {
- *(tfd->sdata) = iroundf(tfd->val);
+ *(tfd->sdata) = round_fl_to_int(tfd->val);
}
}
@@ -4606,7 +4789,7 @@ void flushTransGraphData(TransInfo *t)
/* if int-values only, truncate to integers */
if (td->flag & TD_INTVALUES)
- td2d->loc2d[1] = floorf(td2d->loc[1] + 0.5f);
+ td2d->loc2d[1] = floorf(td2d->loc[1] * inv_unit_scale - tdg->offset + 0.5f);
else
td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset;
@@ -5259,7 +5442,8 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
}
/* update object's loc/rot to get current rigid body transform */
mat4_to_loc_rot_size(ob->loc, rot, scale, ob->obmat);
- BKE_object_mat3_to_rot(ob, rot, false);
+ sub_v3_v3(ob->loc, ob->dloc);
+ BKE_object_mat3_to_rot(ob, rot, false); /* drot is already corrected here */
}
}
@@ -5422,9 +5606,7 @@ static void set_trans_object_base_flags(TransInfo *t)
}
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
-#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
-#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
@@ -5503,9 +5685,7 @@ static int count_proportional_objects(TransInfo *t)
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
DAG_scene_relations_update(G.main, t->scene);
-#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
-#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
@@ -5792,27 +5972,23 @@ static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
{
SpaceClip *sc = t->sa->spacedata.first;
MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTrackingPlaneTrack *plane_track;
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- for (plane_track = plane_tracks_base->first;
+ const int framenr = ED_space_clip_get_clip_frame_number(sc);
+ /* Update coordinates of modified plane tracks. */
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
plane_track;
plane_track = plane_track->next)
{
bool do_update = false;
-
if (plane_track->flag & PLANE_TRACK_HIDDEN) {
continue;
}
-
do_update |= PLANE_TRACK_VIEW_SELECTED(plane_track) != 0;
if (do_update == false) {
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
int i;
for (i = 0; i < plane_track->point_tracksnr; i++) {
MovieTrackingTrack *track = plane_track->point_tracks[i];
-
if (TRACK_VIEW_SELECTED(sc, track)) {
do_update = true;
break;
@@ -5820,15 +5996,14 @@ static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
}
}
}
-
if (do_update) {
BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
}
}
-
- if (t->scene->nodetree) {
- /* tracks can be used for stabilization nodes,
- * flush update for such nodes */
+ if (t->scene->nodetree != NULL) {
+ /* Tracks can be used for stabilization nodes,
+ * flush update for such nodes.
+ */
nodeUpdateID(t->scene->nodetree, &clip->id);
WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
}
@@ -7656,7 +7831,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
float mtx[3][3], smtx[3][3];
const Scene *scene = CTX_data_scene(C);
- const int cfra = CFRA;
+ const int cfra_scene = CFRA;
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
@@ -7681,7 +7856,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
-
+
for (gps = gpf->strokes.first; gps; gps = gps->next) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
@@ -7737,6 +7912,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
float diff_mat[4][4];
@@ -7753,7 +7929,6 @@ static void createTransGPencil(bContext *C, TransInfo *t)
* - This is useful when animating as it saves that "uh-oh" moment when you realize you've
* spent too much time editing the wrong frame...
*/
- // XXX: should this be allowed when framelock is enabled?
if (gpf->framenum != cfra) {
gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
/* in some weird situations (framelock enabled) return NULL */
@@ -8033,7 +8208,12 @@ void createTransData(bContext *C, TransInfo *t)
if (t->data && t->flag & T_PROP_EDIT) {
if (ELEM(t->obedit->type, OB_CURVE, OB_MESH)) {
sort_trans_data(t); // makes selected become first in array
- set_prop_dist(t, 0);
+ if ((t->obedit->type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) {
+ /* already calculated by editmesh_set_connectivity_distance */
+ }
+ else {
+ set_prop_dist(t, 0);
+ }
sort_trans_data_dist(t);
}
else {
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index f78a23be7b8..179b68dd270 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -971,7 +971,7 @@ static void recalcData_sequencer(TransInfo *t)
/* force recalculation of triangles during transformation */
static void recalcData_gpencil_strokes(TransInfo *t)
- {
+{
TransData *td = t->data;
for (int i = 0; i < t->total; i++, td++) {
bGPDstroke *gps = td->extra;
@@ -1331,7 +1331,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->current_orientation = V3D_MANIP_GLOBAL;
}
}
-
+
if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
RNA_property_is_set(op->ptr, prop)))
{
@@ -1435,6 +1435,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
#endif
setTransformViewAspect(t, t->aspect);
+
+ if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, t->center);
+ mul_v3_v3(t->center, t->aspect);
+ t->flag |= T_OVERRIDE_CENTER;
+ }
+
setTransformViewMatrices(t);
initNumInput(&t->num);
}
@@ -1835,7 +1842,9 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[
void calculateCenter(TransInfo *t)
{
- calculateCenter_FromAround(t, t->around, t->center);
+ if ((t->flag & T_OVERRIDE_CENTER) == 0) {
+ calculateCenter_FromAround(t, t->around, t->center);
+ }
calculateCenterGlobal(t, t->center, t->center_global);
/* avoid calculating again */
@@ -1849,7 +1858,7 @@ void calculateCenter(TransInfo *t)
calculateCenter2D(t);
/* for panning from cameraview */
- if (t->flag & T_OBJECT) {
+ if ((t->flag & T_OBJECT) && (t->flag & T_OVERRIDE_CENTER) == 0) {
if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
if (t->flag & T_CAMERA) {
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index 9b7d19eacd5..5f2e5a99090 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -86,12 +86,11 @@ static void InputTrackBall(TransInfo *UNUSED(t), MouseInput *mi, const double mv
output[1] *= mi->factor;
}
-static void InputHorizontalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3])
+static void InputHorizontalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
const int winx = t->ar ? t->ar->winx : 1;
- const double pad = winx / 10;
- output[0] = (mval[0] - pad) / (winx - 2 * pad);
+ output[0] = ((mval[0] - mi->imval[0]) / winx) * 2.0f;
}
static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
@@ -104,12 +103,11 @@ static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double m
output[0] = dot_v3v3(t->viewinv[0], vec) * 2.0f;
}
-static void InputVerticalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3])
+static void InputVerticalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
const int winy = t->ar ? t->ar->winy : 1;
- const double pad = winy / 10;
- output[0] = (mval[1] - pad) / (winy - 2 * pad);
+ output[0] = ((mval[1] - mi->imval[1]) / winy) * 2.0f;
}
static void InputVerticalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
@@ -187,7 +185,7 @@ static void InputAngle(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2
/* use doubles here, to make sure a "1.0" (no rotation) doesn't become 9.999999e-01, which gives 0.02 for acos */
double deler = (((dx1 * dx1 + dy1 * dy1) +
(dx2 * dx2 + dy2 * dy2) -
- (dx3 * dx3 + dy3 * dy3)) / (2.0 * ((A * B) ? (A * B) : 1.0)));
+ (dx3 * dx3 + dy3 * dy3)) / (2.0 * (((A * B) != 0.0) ? (A * B) : 1.0)));
/* ((A * B) ? (A * B) : 1.0) this takes care of potential divide by zero errors */
float dphi;
@@ -234,10 +232,10 @@ static void InputAngleSpring(TransInfo *t, MouseInput *mi, const double mval[2],
output[1] = toutput[0];
}
-void initMouseInput(TransInfo *UNUSED(t), MouseInput *mi, const float center[2], const int mval[2])
+void initMouseInput(TransInfo *UNUSED(t), MouseInput *mi, const float center[2], const int mval[2], const bool precision)
{
mi->factor = 0;
- mi->precision = 0;
+ mi->precision = precision;
mi->center[0] = center[0];
mi->center[1] = center[1];
@@ -314,7 +312,6 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
t->helpline = HLP_TRACKBALL;
break;
case INPUT_HORIZONTAL_RATIO:
- mi->factor = (float)(mi->center[0] - mi->imval[0]);
mi->apply = InputHorizontalRatio;
t->helpline = HLP_HARROW;
break;
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 075f311db72..9a362ee609f 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -107,15 +107,16 @@
#define TW_AXIS_DOT_MIN 0.02f
#define TW_AXIS_DOT_MAX 0.1f
+struct TransformBounds {
+ float center[3]; /* Center for transform widget. */
+ float min[3], max[3]; /* Boundbox of selection for transform widget. */
+};
+
/* transform widget center calc helper for below */
-static void calc_tw_center(Scene *scene, const float co[3])
+static void calc_tw_center(struct TransformBounds *tbounds, const float co[3])
{
- float *twcent = scene->twcent;
- float *min = scene->twmin;
- float *max = scene->twmax;
-
- minmax_v3v3_v3(min, max, co);
- add_v3_v3(twcent, co);
+ minmax_v3v3_v3(tbounds->min, tbounds->max, co);
+ add_v3_v3(tbounds->center, co);
}
static void protectflag_to_drawflags(short protectflag, short *drawflags)
@@ -143,21 +144,17 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags)
}
/* for pose mode */
-static void stats_pose(Scene *scene, RegionView3D *rv3d, bPoseChannel *pchan)
+static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan)
{
- Bone *bone = pchan->bone;
-
- if (bone) {
- calc_tw_center(scene, pchan->pose_head);
- protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
- }
+ protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
}
/* for editmode*/
-static void stats_editbone(RegionView3D *rv3d, EditBone *ebo)
+static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo)
{
- if (ebo->flag & BONE_EDITMODE_LOCKED)
+ if (ebo->flag & BONE_EDITMODE_LOCKED) {
protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag);
+ }
}
/* could move into BLI_math however this is only useful for display/editing purposes */
@@ -192,73 +189,71 @@ static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], con
}
-static int test_rotmode_euler(short rotmode)
+static bool test_rotmode_euler(short rotmode)
{
return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1;
}
bool gimbal_axis(Object *ob, float gmat[3][3])
{
- if (ob) {
- if (ob->mode & OB_MODE_POSE) {
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
-
- if (pchan) {
- float mat[3][3], tmat[3][3], obmat[3][3];
- if (test_rotmode_euler(pchan->rotmode)) {
- eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
- }
- else { /* quat */
- return 0;
- }
-
-
- /* apply bone transformation */
- mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
-
- if (pchan->parent) {
- float parent_mat[3][3];
+ if (ob->mode & OB_MODE_POSE) {
+ bPoseChannel *pchan = BKE_pose_channel_active(ob);
- copy_m3_m4(parent_mat, pchan->parent->pose_mat);
- mul_m3_m3m3(mat, parent_mat, tmat);
-
- /* needed if object transformation isn't identity */
- copy_m3_m4(obmat, ob->obmat);
- mul_m3_m3m3(gmat, obmat, mat);
- }
- else {
- /* needed if object transformation isn't identity */
- copy_m3_m4(obmat, ob->obmat);
- mul_m3_m3m3(gmat, obmat, tmat);
- }
-
- normalize_m3(gmat);
- return 1;
+ if (pchan) {
+ float mat[3][3], tmat[3][3], obmat[3][3];
+ if (test_rotmode_euler(pchan->rotmode)) {
+ eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
}
- }
- else {
- if (test_rotmode_euler(ob->rotmode)) {
- eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
- }
- else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
}
else { /* quat */
return 0;
}
- if (ob->parent) {
+
+ /* apply bone transformation */
+ mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
+
+ if (pchan->parent) {
float parent_mat[3][3];
- copy_m3_m4(parent_mat, ob->parent->obmat);
- normalize_m3(parent_mat);
- mul_m3_m3m3(gmat, parent_mat, gmat);
+
+ copy_m3_m4(parent_mat, pchan->parent->pose_mat);
+ mul_m3_m3m3(mat, parent_mat, tmat);
+
+ /* needed if object transformation isn't identity */
+ copy_m3_m4(obmat, ob->obmat);
+ mul_m3_m3m3(gmat, obmat, mat);
+ }
+ else {
+ /* needed if object transformation isn't identity */
+ copy_m3_m4(obmat, ob->obmat);
+ mul_m3_m3m3(gmat, obmat, tmat);
}
+
+ normalize_m3(gmat);
return 1;
}
}
+ else {
+ if (test_rotmode_euler(ob->rotmode)) {
+ eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
+ }
+ else if (ob->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
+ }
+ else { /* quat */
+ return 0;
+ }
+
+ if (ob->parent) {
+ float parent_mat[3][3];
+ copy_m3_m4(parent_mat, ob->parent->obmat);
+ normalize_m3(parent_mat);
+ mul_m3_m3m3(gmat, parent_mat, gmat);
+ }
+ return 1;
+ }
return 0;
}
@@ -266,7 +261,7 @@ bool gimbal_axis(Object *ob, float gmat[3][3])
/* centroid, boundbox, of selection */
/* returns total items selected */
-static int calc_manipulator_stats(const bContext *C)
+static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbounds)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -286,9 +281,9 @@ static int calc_manipulator_stats(const bContext *C)
rv3d->twdrawflag = 0xFFFF;
/* transform widget centroid/center */
- INIT_MINMAX(scene->twmin, scene->twmax);
- zero_v3(scene->twcent);
-
+ INIT_MINMAX(tbounds->min, tbounds->max);
+ zero_v3(tbounds->center);
+
if (is_gp_edit) {
float diff_mat[4][4];
float fpt[3];
@@ -317,12 +312,12 @@ static int calc_manipulator_stats(const bContext *C)
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
if (gpl->parent == NULL) {
- calc_tw_center(scene, &pt->x);
+ calc_tw_center(tbounds, &pt->x);
totsel++;
}
else {
mul_v3_m4v3(fpt, diff_mat, &pt->x);
- calc_tw_center(scene, fpt);
+ calc_tw_center(tbounds, fpt);
totsel++;
}
}
@@ -335,7 +330,7 @@ static int calc_manipulator_stats(const bContext *C)
/* selection center */
if (totsel) {
- mul_v3_fl(scene->twcent, 1.0f / (float)totsel); /* centroid! */
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel);
}
}
else if (obedit) {
@@ -350,7 +345,7 @@ static int calc_manipulator_stats(const bContext *C)
/* USE LAST SELECTE WITH ACTIVE */
if ((v3d->around == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
BM_editselection_center(&ese, vec);
- calc_tw_center(scene, vec);
+ calc_tw_center(tbounds, vec);
totsel = 1;
}
else {
@@ -363,7 +358,7 @@ static int calc_manipulator_stats(const bContext *C)
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
totsel++;
- calc_tw_center(scene, eve->co);
+ calc_tw_center(tbounds, eve->co);
}
}
}
@@ -376,22 +371,22 @@ static int calc_manipulator_stats(const bContext *C)
if ((v3d->around == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) {
/* doesn't check selection or visibility intentionally */
if (ebo->flag & BONE_TIPSEL) {
- calc_tw_center(scene, ebo->tail);
+ calc_tw_center(tbounds, ebo->tail);
totsel++;
}
if ((ebo->flag & BONE_ROOTSEL) ||
((ebo->flag & BONE_TIPSEL) == false)) /* ensure we get at least one point */
{
- calc_tw_center(scene, ebo->head);
+ calc_tw_center(tbounds, ebo->head);
totsel++;
}
- stats_editbone(rv3d, ebo);
+ protectflag_to_drawflags_ebone(rv3d, ebo);
}
else {
for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
if (EBONE_VISIBLE(arm, ebo)) {
if (ebo->flag & BONE_TIPSEL) {
- calc_tw_center(scene, ebo->tail);
+ calc_tw_center(tbounds, ebo->tail);
totsel++;
}
if ((ebo->flag & BONE_ROOTSEL) &&
@@ -401,11 +396,11 @@ static int calc_manipulator_stats(const bContext *C)
(ebo->parent->flag & BONE_TIPSEL) &&
EBONE_VISIBLE(arm, ebo->parent)) == 0)
{
- calc_tw_center(scene, ebo->head);
+ calc_tw_center(tbounds, ebo->head);
totsel++;
}
if (ebo->flag & BONE_SELECTED) {
- stats_editbone(rv3d, ebo);
+ protectflag_to_drawflags_ebone(rv3d, ebo);
}
}
}
@@ -416,7 +411,7 @@ static int calc_manipulator_stats(const bContext *C)
float center[3];
if (v3d->around == V3D_AROUND_ACTIVE && ED_curve_active_center(cu, center)) {
- calc_tw_center(scene, center);
+ calc_tw_center(tbounds, center);
totsel++;
}
else {
@@ -437,21 +432,25 @@ static int calc_manipulator_stats(const bContext *C)
*/
if (cu->drawflag & CU_HIDE_HANDLES) {
if (bezt->f2 & SELECT) {
- calc_tw_center(scene, bezt->vec[1]);
+ calc_tw_center(tbounds, bezt->vec[1]);
totsel++;
}
}
else if (bezt->f2 & SELECT) {
- calc_tw_center(scene, bezt->vec[1]);
+ calc_tw_center(tbounds, bezt->vec[1]);
totsel++;
}
else {
if (bezt->f1 & SELECT) {
- calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]);
+ calc_tw_center(
+ tbounds,
+ bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]);
totsel++;
}
if (bezt->f3 & SELECT) {
- calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]);
+ calc_tw_center(
+ tbounds,
+ bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]);
totsel++;
}
}
@@ -463,7 +462,7 @@ static int calc_manipulator_stats(const bContext *C)
a = nu->pntsu * nu->pntsv;
while (a--) {
if (bp->f1 & SELECT) {
- calc_tw_center(scene, bp->vec);
+ calc_tw_center(tbounds, bp->vec);
totsel++;
}
bp++;
@@ -478,13 +477,13 @@ static int calc_manipulator_stats(const bContext *C)
MetaElem *ml;
if ((v3d->around == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) {
- calc_tw_center(scene, &ml->x);
+ calc_tw_center(tbounds, &ml->x);
totsel++;
}
else {
for (ml = mb->editelems->first; ml; ml = ml->next) {
if (ml->flag & SELECT) {
- calc_tw_center(scene, &ml->x);
+ calc_tw_center(tbounds, &ml->x);
totsel++;
}
}
@@ -495,7 +494,7 @@ static int calc_manipulator_stats(const bContext *C)
BPoint *bp;
if ((v3d->around == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) {
- calc_tw_center(scene, bp->vec);
+ calc_tw_center(tbounds, bp->vec);
totsel++;
}
else {
@@ -503,7 +502,7 @@ static int calc_manipulator_stats(const bContext *C)
a = lt->pntsu * lt->pntsv * lt->pntsw;
while (a--) {
if (bp->f1 & SELECT) {
- calc_tw_center(scene, bp->vec);
+ calc_tw_center(tbounds, bp->vec);
totsel++;
}
bp++;
@@ -513,10 +512,10 @@ static int calc_manipulator_stats(const bContext *C)
/* selection center */
if (totsel) {
- mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
- mul_m4_v3(obedit->obmat, scene->twcent);
- mul_m4_v3(obedit->obmat, scene->twmin);
- mul_m4_v3(obedit->obmat, scene->twmax);
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel);
+ mul_m4_v3(obedit->obmat, tbounds->center);
+ mul_m4_v3(obedit->obmat, tbounds->min);
+ mul_m4_v3(obedit->obmat, tbounds->max);
}
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
@@ -530,7 +529,8 @@ static int calc_manipulator_stats(const bContext *C)
/* doesn't check selection or visibility intentionally */
Bone *bone = pchan->bone;
if (bone) {
- stats_pose(scene, rv3d, pchan);
+ calc_tw_center(tbounds, pchan->pose_head);
+ protectflag_to_drawflags_pchan(rv3d, pchan);
totsel = 1;
ok = true;
}
@@ -543,7 +543,8 @@ static int calc_manipulator_stats(const bContext *C)
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
Bone *bone = pchan->bone;
if (bone && (bone->flag & BONE_TRANSFORM)) {
- stats_pose(scene, rv3d, pchan);
+ calc_tw_center(tbounds, pchan->pose_head);
+ protectflag_to_drawflags_pchan(rv3d, pchan);
}
}
ok = true;
@@ -551,10 +552,10 @@ static int calc_manipulator_stats(const bContext *C)
}
if (ok) {
- mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
- mul_m4_v3(ob->obmat, scene->twcent);
- mul_m4_v3(ob->obmat, scene->twmin);
- mul_m4_v3(ob->obmat, scene->twmax);
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel);
+ mul_m4_v3(ob->obmat, tbounds->center);
+ mul_m4_v3(ob->obmat, tbounds->min);
+ mul_m4_v3(ob->obmat, tbounds->max);
}
}
else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
@@ -573,7 +574,7 @@ static int calc_manipulator_stats(const bContext *C)
for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) {
if (ek->flag & PEK_SELECT) {
- calc_tw_center(scene, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
+ calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
totsel++;
}
}
@@ -581,7 +582,7 @@ static int calc_manipulator_stats(const bContext *C)
/* selection center */
if (totsel)
- mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel);
}
}
else {
@@ -594,7 +595,7 @@ static int calc_manipulator_stats(const bContext *C)
if (TESTBASELIB(v3d, base)) {
if (ob == NULL)
ob = base->object;
- calc_tw_center(scene, base->object->obmat[3]);
+ calc_tw_center(tbounds, base->object->obmat[3]);
protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
totsel++;
}
@@ -602,7 +603,7 @@ static int calc_manipulator_stats(const bContext *C)
/* selection center */
if (totsel) {
- mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel);
}
}
@@ -623,7 +624,7 @@ static int calc_manipulator_stats(const bContext *C)
break;
}
/* if not gimbal, fall through to normal */
- /* fall-through */
+ ATTR_FALLTHROUGH;
}
case V3D_MANIP_NORMAL:
{
@@ -634,7 +635,7 @@ static int calc_manipulator_stats(const bContext *C)
break;
}
/* no break we define 'normal' as 'local' in Object mode */
- /* fall-through */
+ ATTR_FALLTHROUGH;
}
case V3D_MANIP_LOCAL:
{
@@ -1647,9 +1648,10 @@ void BIF_draw_manipulator(const bContext *C)
if ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) == 0) return;
{
+ struct TransformBounds tbounds;
v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
- totsel = calc_manipulator_stats(C);
+ totsel = calc_manipulator_stats(C, &tbounds);
if (totsel == 0) return;
v3d->twflag |= V3D_DRAW_MANIPULATOR;
@@ -1669,13 +1671,13 @@ void BIF_draw_manipulator(const bContext *C)
copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
}
else {
- mid_v3_v3v3(rv3d->twmat[3], scene->twmin, scene->twmax);
+ mid_v3_v3v3(rv3d->twmat[3], tbounds.min, tbounds.max);
}
break;
}
case V3D_AROUND_LOCAL_ORIGINS:
case V3D_AROUND_CENTER_MEAN:
- copy_v3_v3(rv3d->twmat[3], scene->twcent);
+ copy_v3_v3(rv3d->twmat[3], tbounds.center);
break;
case V3D_AROUND_CURSOR:
copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d));
@@ -1720,19 +1722,16 @@ void BIF_draw_manipulator(const bContext *C)
}
}
-static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], float hotspot)
+static int manipulator_selectbuf(Scene *scene, ScrArea *sa, ARegion *ar, const int mval[2], float hotspot)
{
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
- rctf rect, selrect;
+ rcti rect;
GLuint buffer[64]; // max 4 items per select, so large enuf
short hits;
const bool is_picksel = true;
const bool do_passes = GPU_select_query_check_active();
- /* XXX check a bit later on this... (ton) */
- extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect);
-
/* when looking through a selected camera, the manipulator can be at the
* exact same position as the view, skip so we don't break selection */
if (fabsf(mat4_to_scale(rv3d->twmat)) < 1e-7f)
@@ -1743,15 +1742,12 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
rect.ymin = mval[1] - hotspot;
rect.ymax = mval[1] + hotspot;
- selrect = rect;
-
- view3d_winmatrix_set(ar, v3d, &rect);
- mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
+ ED_view3d_draw_setup_view(NULL, scene, ar, v3d, NULL, NULL, &rect);
if (do_passes)
- GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
+ GPU_select_begin(buffer, 64, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
else
- GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_ALL, 0);
+ GPU_select_begin(buffer, 64, &rect, GPU_SELECT_ALL, 0);
/* do the drawing */
if (v3d->twtype & V3D_MANIP_ROTATE) {
@@ -1765,8 +1761,8 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
hits = GPU_select_end();
- if (do_passes) {
- GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+ if (do_passes && (hits > 0)) {
+ GPU_select_begin(buffer, 64, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
/* do the drawing */
if (v3d->twtype & V3D_MANIP_ROTATE) {
@@ -1781,8 +1777,7 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
GPU_select_end();
}
- view3d_winmatrix_set(ar, v3d, NULL);
- mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
+ ED_view3d_draw_setup_view(NULL, scene, ar, v3d, NULL, NULL, NULL);
if (hits == 1) return buffer[3];
else if (hits > 1) {
@@ -1826,16 +1821,34 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
return 0;
}
+static const char *manipulator_get_operator_name(int man_val)
+{
+ if (man_val & MAN_TRANS_C) {
+ return "TRANSFORM_OT_translate";
+ }
+ else if (man_val == MAN_ROT_T) {
+ return "TRANSFORM_OT_trackball";
+ }
+ else if (man_val & MAN_ROT_C) {
+ return "TRANSFORM_OT_rotate";
+ }
+ else if (man_val & MAN_SCALE_C) {
+ return "TRANSFORM_OT_resize";
+ }
+
+ return NULL;
+}
/* return 0; nothing happened */
int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
ScrArea *sa = CTX_wm_area(C);
View3D *v3d = sa->spacedata.first;
ARegion *ar = CTX_wm_region(C);
int constraint_axis[3] = {0, 0, 0};
int val;
- int shift = event->shift;
+ const bool use_planar = RNA_boolean_get(op->ptr, "use_planar_constraint");
if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0;
if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0;
@@ -1844,19 +1857,32 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
RNA_enum_set(op->ptr, "constraint_orientation", v3d->twmode);
// find the hotspots first test narrow hotspot
- val = manipulator_selectbuf(sa, ar, event->mval, 0.5f * (float)U.tw_hotspot);
+ val = manipulator_selectbuf(scene, sa, ar, event->mval, 0.5f * (float)U.tw_hotspot);
if (val) {
+ wmOperatorType *ot;
+ PointerRNA props_ptr;
+ PropertyRNA *prop;
+ const char *opname;
// drawflags still global, for drawing call above
- drawflags = manipulator_selectbuf(sa, ar, event->mval, 0.2f * (float)U.tw_hotspot);
+ drawflags = manipulator_selectbuf(scene, sa, ar, event->mval, 0.2f * (float)U.tw_hotspot);
if (drawflags == 0) drawflags = val;
+ /* Planar constraint doesn't make sense for rotation, give other keymaps a chance */
+ if ((drawflags & MAN_ROT_C) && use_planar) {
+ return 0;
+ }
+
+ opname = manipulator_get_operator_name(drawflags);
+ ot = WM_operatortype_find(opname, true);
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+
if (drawflags & MAN_TRANS_C) {
switch (drawflags) {
case MAN_TRANS_C:
break;
case MAN_TRANS_X:
- if (shift) {
+ if (use_planar) {
constraint_axis[1] = 1;
constraint_axis[2] = 1;
}
@@ -1864,7 +1890,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
constraint_axis[0] = 1;
break;
case MAN_TRANS_Y:
- if (shift) {
+ if (use_planar) {
constraint_axis[0] = 1;
constraint_axis[2] = 1;
}
@@ -1872,7 +1898,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
constraint_axis[1] = 1;
break;
case MAN_TRANS_Z:
- if (shift) {
+ if (use_planar) {
constraint_axis[0] = 1;
constraint_axis[1] = 1;
}
@@ -1880,13 +1906,12 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
constraint_axis[2] = 1;
break;
}
- RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
- WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_DEFAULT, op->ptr);
+ RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis);
}
else if (drawflags & MAN_SCALE_C) {
switch (drawflags) {
case MAN_SCALE_X:
- if (shift) {
+ if (use_planar) {
constraint_axis[1] = 1;
constraint_axis[2] = 1;
}
@@ -1894,7 +1919,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
constraint_axis[0] = 1;
break;
case MAN_SCALE_Y:
- if (shift) {
+ if (use_planar) {
constraint_axis[0] = 1;
constraint_axis[2] = 1;
}
@@ -1902,7 +1927,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
constraint_axis[1] = 1;
break;
case MAN_SCALE_Z:
- if (shift) {
+ if (use_planar) {
constraint_axis[0] = 1;
constraint_axis[1] = 1;
}
@@ -1910,22 +1935,10 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
constraint_axis[2] = 1;
break;
}
- RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
- WM_operator_name_call(C, "TRANSFORM_OT_resize", WM_OP_INVOKE_DEFAULT, op->ptr);
+ RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis);
}
- else if (drawflags == MAN_ROT_T) { /* trackball need special case, init is different */
- /* Do not pass op->ptr!!! trackball has no "constraint" properties!
- * See [#34621], it's a miracle it did not cause more problems!!! */
- /* However, we need to copy the "release_confirm" property, but only if defined, see T41112. */
- PointerRNA props_ptr;
- PropertyRNA *prop;
- wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_trackball", true);
- WM_operator_properties_create_ptr(&props_ptr, ot);
- if ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop));
- }
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
- WM_operator_properties_free(&props_ptr);
+ else if (drawflags == MAN_ROT_T) {
+ /* pass */
}
else if (drawflags & MAN_ROT_C) {
switch (drawflags) {
@@ -1939,9 +1952,25 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
constraint_axis[2] = 1;
break;
}
- RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
- WM_operator_name_call(C, "TRANSFORM_OT_rotate", WM_OP_INVOKE_DEFAULT, op->ptr);
+ RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis);
+ }
+
+ /* pass operator properties on to transform operators */
+ prop = RNA_struct_find_property(op->ptr, "use_accurate");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop));
}
+ prop = RNA_struct_find_property(op->ptr, "release_confirm");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop));
+ }
+ prop = RNA_struct_find_property(op->ptr, "constraint_orientation");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_enum_set(&props_ptr, prop, RNA_property_enum_get(op->ptr, prop));
+ }
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
+ WM_operator_properties_free(&props_ptr);
}
/* after transform, restore drawflags */
drawflags = 0xFFFF;
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index cbe58ddf586..0bdee594e80 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -565,10 +565,20 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
RNA_def_boolean(ot->srna, "correct_uv", 0, "Correct UVs", "Correct UV coordinates when transforming");
}
+ if (flags & P_CENTER) {
+ /* For manipulators that define their own center. */
+ prop = RNA_def_property(ot->srna, "center_override", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ RNA_def_property_ui_text(prop, "Center Override", "Force using this center value (when set)");
+ }
+
if ((flags & P_NO_DEFAULTS) == 0) {
- // Add confirm method all the time. At the end because it's not really that important and should be hidden only in log, not in keymap edit
- /*prop =*/ RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "Always confirm operation when releasing button");
- //RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "Always confirm operation when releasing button");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ prop = RNA_def_boolean(ot->srna, "use_accurate", 0, "Accurate", "Use accurate transformation");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
}
@@ -609,7 +619,8 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT);
+ Transform_Properties(
+ ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT | P_CENTER);
}
static int skin_resize_poll(bContext *C)
@@ -660,7 +671,7 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
/* Maybe we could use float_vector_xyz here too? */
RNA_def_float_rotation(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
@@ -680,7 +691,8 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
- Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT);
+ Transform_Properties(
+ ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
@@ -723,7 +735,7 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot)
RNA_def_float_rotation(ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
@@ -764,7 +776,7 @@ static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot)
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Distance", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_CENTER);
}
static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot)
@@ -807,7 +819,7 @@ static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
@@ -825,7 +837,7 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
ot->cancel = transform_cancel;
ot->poll = ED_operator_screenactive;
- Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT);
+ Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER);
}
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
@@ -988,7 +1000,8 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "value", 4, NULL, -FLT_MAX, FLT_MAX, "Values", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT);
+ Transform_Properties(
+ ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
void transform_operatortypes(void)
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 90a4aa3614d..54959304d72 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -42,7 +42,7 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
-#include "BLI_path_util.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
@@ -451,18 +451,18 @@ void initTransformOrientation(bContext *C, TransInfo *t)
case V3D_MANIP_GIMBAL:
unit_m3(t->spacemtx);
- if (gimbal_axis(ob, t->spacemtx)) {
+ if (ob && gimbal_axis(ob, t->spacemtx)) {
BLI_strncpy(t->spacename, IFACE_("gimbal"), sizeof(t->spacename));
break;
}
- /* fall-through */ /* no gimbal fallthrough to normal */
+ ATTR_FALLTHROUGH; /* no gimbal fallthrough to normal */
case V3D_MANIP_NORMAL:
if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
BLI_strncpy(t->spacename, IFACE_("normal"), sizeof(t->spacename));
ED_getTransformOrientationMatrix(C, t->spacemtx, t->around);
break;
}
- /* fall-through */ /* we define 'normal' as 'local' in Object mode */
+ ATTR_FALLTHROUGH; /* we define 'normal' as 'local' in Object mode */
case V3D_MANIP_LOCAL:
BLI_strncpy(t->spacename, IFACE_("local"), sizeof(t->spacename));
@@ -817,15 +817,21 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
Curve *cu = obedit->data;
Nurb *nu = NULL;
- BezTriple *bezt = NULL;
int a;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bezt)) {
+ void *vert_act = NULL;
+ if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, &vert_act)) {
if (nu->type == CU_BEZIER) {
+ BezTriple *bezt = vert_act;
BKE_nurb_bezt_calc_normal(nu, bezt, normal);
BKE_nurb_bezt_calc_plane(nu, bezt, plane);
}
+ else {
+ BPoint *bp = vert_act;
+ BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+ BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+ }
}
else {
const bool use_handle = (cu->drawflag & CU_HIDE_HANDLES) == 0;
@@ -833,7 +839,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
for (nu = nurbs->first; nu; nu = nu->next) {
/* only bezier has a normal */
if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
+ BezTriple *bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
short flag = 0;
@@ -885,6 +891,36 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
bezt++;
}
}
+ else if (nu->bp && (nu->pntsv == 1)) {
+ BPoint *bp = nu->bp;
+ a = nu->pntsu;
+ while (a--) {
+ if (bp->f1 & SELECT) {
+ float tvec[3];
+
+ BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
+ BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
+
+ const bool is_prev_sel = bp_prev && (bp_prev->f1 & SELECT);
+ const bool is_next_sel = bp_next && (bp_next->f1 & SELECT);
+ if (is_prev_sel == false && is_next_sel == false) {
+ /* Isolated, add based on surrounding */
+ BKE_nurb_bpoint_calc_normal(nu, bp, tvec);
+ add_v3_v3(normal, tvec);
+ }
+ else if (is_next_sel) {
+ /* A segment, add the edge normal */
+ sub_v3_v3v3(tvec, bp->vec, bp_next->vec );
+ normalize_v3(tvec);
+ add_v3_v3(normal, tvec);
+ }
+
+ BKE_nurb_bpoint_calc_plane(nu, bp, tvec);
+ add_v3_v3(plane, tvec);
+ }
+ bp++;
+ }
+ }
}
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index f8bb124e943..4a7c2decf95 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -569,7 +569,9 @@ static void initSnappingMode(TransInfo *t)
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
(obedit == NULL) ) // Object Mode
{
- t->tsnap.modeSelect = SNAP_NOT_SELECTED;
+ /* In "Edit Strokes" mode, Snap tool can perform snap to selected or active objects (see T49632)
+ * TODO: perform self snap in gpencil_strokes */
+ t->tsnap.modeSelect = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_ALL : SNAP_NOT_SELECTED;
}
else {
/* Grid if snap is not possible */
@@ -599,7 +601,7 @@ 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,
+ G.main, t->scene, 0,
t->ar, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
@@ -1015,7 +1017,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
char node_border;
- if (snapNodesTransform(t, t->mval, t->tsnap.modeSelect, loc, &dist_px, &node_border)) {
+ if (snapNodesTransform(t, t->mval, loc, &dist_px, &node_border)) {
copy_v2_v2(t->tsnap.snapPoint, loc);
t->tsnap.snapNodeBorder = node_border;
@@ -1214,7 +1216,7 @@ bool snapObjectsTransform(
t->tsnap.object_context,
t->scene->toolsettings->snap_mode,
&(const struct SnapObjectParams){
- .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
},
mval, dist_px, NULL,
@@ -1304,7 +1306,7 @@ bool peelObjectsTransform(
t->tsnap.object_context,
mval,
&(const struct SnapObjectParams){
- .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
},
use_peel_object,
@@ -1411,22 +1413,11 @@ static bool snapNodes(
}
bool snapNodesTransform(
- TransInfo *t, const int mval[2], SnapSelect snap_select,
- float r_loc[2], float *r_dist_px, char *r_node_border)
-{
- return snapNodes(
- t->settings, t->sa->spacedata.first, t->ar, mval, snap_select,
- r_loc, r_dist_px, r_node_border);
-}
-
-bool snapNodesContext(
- bContext *C, const int mval[2], SnapSelect snap_select,
+ TransInfo *t, const int mval[2],
float r_loc[2], float *r_dist_px, char *r_node_border)
{
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
return snapNodes(
- scene->toolsettings, CTX_wm_space_node(C), ar, mval, snap_select,
+ t->settings, t->sa->spacedata.first, t->ar, mval, t->tsnap.modeSelect,
r_loc, r_dist_px, r_node_border);
}
@@ -1476,7 +1467,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2])
/* convert to frame range */
UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse);
- mframe = iroundf(xmouse);
+ mframe = round_fl_to_int(xmouse);
/* now find the closest sequence */
frame = BKE_sequencer_find_next_prev_edit(t->scene, mframe, SEQ_SIDE_BOTH, true, false, true);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 02900d7022c..1fdf7c67cff 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -59,6 +59,24 @@
#include "transform.h"
+enum eViewProj {
+ VIEW_PROJ_NONE = -1,
+ VIEW_PROJ_ORTHO = 0,
+ VIEW_PROJ_PERSP = -1,
+};
+
+typedef struct SnapData {
+ short snap_to;
+ float mval[2];
+ float ray_origin[3];
+ float ray_start[3];
+ float ray_dir[3];
+ float pmat[4][4]; /* perspective matrix */
+ float win_half[2];/* win x and y */
+ enum eViewProj view_proj;
+ float depth_range[2];
+} SnapData;
+
typedef struct SnapObjectData {
enum {
SNAP_MESH = 1,
@@ -69,6 +87,8 @@ typedef struct SnapObjectData {
typedef struct SnapObjectData_Mesh {
SnapObjectData sd;
BVHTreeFromMesh *bvh_trees[3];
+ MPoly *mpoly;
+ bool poly_allocated;
} SnapObjectData_Mesh;
@@ -110,24 +130,150 @@ struct SnapObjectContext {
};
-enum eViewProj {
- VIEW_PROJ_NONE = -1,
- VIEW_PROJ_ORTHO = 0,
- VIEW_PROJ_PERSP = -1,
-};
-
-static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
+/** \} */
/* -------------------------------------------------------------------- */
-/** \name Support for storing all depths, not just the first (raycast 'all')
+/** Common utilities
+* \{ */
+
+
+typedef void(*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data);
+
+/**
+ * Walks through all objects in the scene to create the list of objets to snap.
*
- * This uses a list of #SnapObjectHitDepth structs.
+ * \param sctx: Snap context to store data.
+ * \param snap_select : from enum SnapSelect.
+ * \param obedit : Object Edited to use its coordinates of BMesh(if any) to do the snapping.
+ */
+static void iter_snap_objects(
+ SnapObjectContext *sctx,
+ const SnapSelect snap_select,
+ Object *obedit,
+ IterSnapObjsCallback sob_callback,
+ void *data)
+{
+ Base *base_act = sctx->scene->basact;
+ /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
+ * which makes the loop skip it, even the derived mesh will never change
+ *
+ * To solve that problem, we do it first as an exception.
+ * */
+ if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {
+ sob_callback(sctx, false, base_act->object, base_act->object->obmat, data);
+ }
+
+ for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) {
+ if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) &&
+ (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
+ !((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL))) ||
+ (snap_select == SNAP_NOT_ACTIVE && base == base_act)))
+ {
+ bool use_obedit;
+ Object *obj = base->object;
+ if (obj->transflag & OB_DUPLI) {
+ DupliObject *dupli_ob;
+ ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, obj);
+ for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
+ use_obedit = obedit && dupli_ob->ob->data == obedit->data;
+ sob_callback(sctx, use_obedit, use_obedit ? obedit : dupli_ob->ob, dupli_ob->mat, data);
+ }
+ free_object_duplilist(lb);
+ }
+
+ use_obedit = obedit && obj->data == obedit->data;
+ sob_callback(sctx, use_obedit, use_obedit ? obedit : obj, obj->obmat, data);
+ }
+ }
+}
+
+
+/**
+ * Generates a struct with the immutable parameters that will be used on all objects.
*
- * \{ */
+ * \param snap_to: Element to snap, Vertice, Edge or Face.
+ * \param view_proj: ORTHO or PERSP.
+ * Currently only works one at a time, but can eventually operate as flag.
+ *
+ * \param mval: Mouse coords.
+ * (When NULL, ray-casting is handled without any projection matrix correction.)
+ * \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_direction: Unit length direction of the ray.
+ * \param depth_range: distances of clipe plane min and clip plane max;
+ */
+static void snap_data_set(
+ SnapData *snapdata,
+ const ARegion *ar, const unsigned short snap_to, const enum eViewProj view_proj,
+ const float mval[2], const float ray_origin[3], const float ray_start[3],
+ const float ray_direction[3], const float depth_range[2])
+{
+ copy_m4_m4(snapdata->pmat, ((RegionView3D *)ar->regiondata)->persmat);
+ snapdata->win_half[0] = ar->winx / 2;
+ snapdata->win_half[1] = ar->winy / 2;
+ copy_v2_v2(snapdata->mval, mval);
+ snapdata->snap_to = snap_to;
+ copy_v3_v3(snapdata->ray_origin, ray_origin);
+ copy_v3_v3(snapdata->ray_start, ray_start);
+ copy_v3_v3(snapdata->ray_dir, ray_direction);
+ snapdata->view_proj = view_proj;
+ copy_v2_v2(snapdata->depth_range, depth_range);
+}
+
+
+MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3])
+{
+ float dvec[3];
+ sub_v3_v3v3(dvec, co, ray_start);
+ return dot_v3v3(dvec, ray_dir);
+}
+
+
+static bool walk_parent_bvhroot_cb(const BVHTreeAxisRange *bounds, void *userdata)
+{
+ BVHTreeRay *ray = userdata;
+ const float bbmin[3] = {bounds[0].min, bounds[1].min, bounds[2].min};
+ const float bbmax[3] = {bounds[0].max, bounds[1].max, bounds[2].max};
+ if (!isect_ray_aabb_v3_simple(ray->origin, ray->direction, bbmin, bbmax, &ray->radius, NULL)) {
+ ray->radius = -1;
+ }
+ return false;
+}
+
+
+static bool isect_ray_bvhroot_v3(struct BVHTree *tree, const float ray_start[3], const float ray_dir[3], float *depth)
+{
+ BVHTreeRay ray;
+ copy_v3_v3(ray.origin, ray_start);
+ copy_v3_v3(ray.direction, ray_dir);
+
+ BLI_bvhtree_walk_dfs(tree, walk_parent_bvhroot_cb, NULL, NULL, &ray);
+
+ if (ray.radius > 0) {
+ *depth = ray.radius;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+
+static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Ray Cast Funcs
+* \{ */
+
+/* Store all ray-hits
+ * Support for storing all depths, not just the first (raycast 'all') */
-/* Store all ray-hits */
struct RayCastAll_Data {
void *bvhdata;
@@ -148,6 +294,7 @@ struct RayCastAll_Data {
bool retval;
};
+
static struct SnapObjectHitDepth *hit_depth_create(
const float depth, const float co[3], const float no[3], int index,
Object *ob, const float obmat[4][4], unsigned int ob_uuid)
@@ -215,208 +362,539 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
}
}
-/** \} */
+static bool raycastDerivedMesh(
+ SnapObjectContext *sctx,
+ const float ray_start[3], const float ray_dir[3],
+ Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
+ /* read/write args */
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ ListBase *r_hit_list)
+{
+ bool retval = false;
+
+ if (dm->getNumPolys(dm) == 0) {
+ return retval;
+ }
-/* -------------------------------------------------------------------- */
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_start_local[3], ray_normal_local[3];
+ float local_scale, local_depth, len_diff = 0.0f;
-/** \Common utilities
- * \{ */
+ 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_dir);
-/**
- * Struct that kepts basic information about a BVHTree build from a editmesh.
- */
-typedef struct BVHTreeFromMeshType {
- void *userdata;
- char type;
-} BVHTreeFromMeshType;
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
-typedef struct PreDefProject {
- float pmat[4][4]; /* perspective matrix multiplied by object matrix */
- float win_half[2];
- float dist_px_sq;
-} PreDefProject;
+ /* 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;
+ }
-static void precalc_project(
- PreDefProject *projectdefs, const ARegion *ar,
- const float dist_px, float obmat[4][4])
-{
- float (*pmat)[4] = ((RegionView3D *)ar->regiondata)->persmat;
- if (obmat) {
- mul_m4_m4m4(projectdefs->pmat, pmat, obmat);
+ /* Test BoundBox */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ if (bb) {
+ /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
+ if (!isect_ray_aabb_v3_simple(
+ ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, NULL))
+ {
+ return retval;
+ }
+ }
+
+ SnapObjectData_Mesh *sod = NULL;
+ BVHTreeFromMesh *treedata;
+
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ sod = *sod_p;
}
else {
- copy_m4_m4(projectdefs->pmat, pmat);
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_MESH;
}
- projectdefs->win_half[0] = ar->winx / 2;
- projectdefs->win_half[1] = ar->winy / 2;
- projectdefs->dist_px_sq = SQUARE(dist_px);
-}
-/**
- * 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];
-}
+ if (sod->bvh_trees[2] == NULL) {
+ sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ }
-static const float *get_vert_co(const BVHTreeFromMeshType *meshdata, const int index)
-{
- switch (meshdata->type) {
- case SNAP_MESH:
- {
- BVHTreeFromMesh *data = meshdata->userdata;
- const MVert *vert = data->vert;
- return vert[index].co;
+ treedata = sod->bvh_trees[2];
+
+ if (treedata) {
+ /* the tree is owned by the DM and may have been freed since we last used! */
+ if (treedata->tree) {
+ if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
+ free_bvhtree_from_mesh(treedata);
+ }
+ else {
+ if (treedata->vert == NULL) {
+ treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated);
+ }
+ if (treedata->loop == NULL) {
+ treedata->loop = DM_get_loop_array(dm, &treedata->loop_allocated);
+ }
+ if (treedata->looptri == NULL) {
+ if (sod->mpoly == NULL) {
+ sod->mpoly = DM_get_poly_array(dm, &sod->poly_allocated);
+ }
+ treedata->looptri = dm->getLoopTriArray(dm);
+ treedata->looptri_allocated = false;
+ }
+ }
}
- case SNAP_EDIT_MESH:
- {
- BVHTreeFromEditMesh *data = meshdata->userdata;
- BMVert *eve = BM_vert_at_index(data->em->bm, index);
- return eve->co;
+
+ if (treedata->tree == NULL) {
+ bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
+
+ if (treedata->tree == NULL) {
+ return retval;
+ }
}
}
- return NULL;
-}
+ else {
+ return retval;
+ }
-static void copy_vert_no(const BVHTreeFromMeshType *meshdata, const int index, float r_no[3])
-{
- switch (meshdata->type) {
- case SNAP_MESH:
- {
- BVHTreeFromMesh *data = meshdata->userdata;
- const MVert *vert = data->vert + index;
- normal_short_to_float_v3(r_no, vert->no);
- break;
+ /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
+ * been *inside* boundbox, leading to snap failures (see T38409).
+ * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
+ */
+ if (len_diff == 0.0f) { /* do_ray_start_correction */
+ /* We *need* a reasonably valid len_diff in this case.
+ * Get the distance to bvhtree root */
+ if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) {
+ return retval;
}
- case SNAP_EDIT_MESH:
+ }
+ /* You need to make sure that ray_start is really far away,
+ * because even in the Orthografic view, in some cases,
+ * the ray can start inside the object (see T50486) */
+ if (len_diff > 400.0f) {
+ /* 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_v3fl(ray_start_local, ray_normal_local, len_diff);
+ local_depth -= len_diff;
+ }
+ else {
+ len_diff = 0.0f;
+ }
+ if (r_hit_list) {
+ struct RayCastAll_Data data;
+
+ data.bvhdata = treedata;
+ data.raycast_callback = treedata->raycast_callback;
+ data.obmat = obmat;
+ data.timat = timat;
+ data.len_diff = len_diff;
+ data.local_scale = local_scale;
+ data.ob = ob;
+ data.ob_uuid = ob_index;
+ data.hit_list = r_hit_list;
+ data.retval = retval;
+
+ BLI_bvhtree_ray_cast_all(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
+
+ retval = data.retval;
+ }
+ else {
+ BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
+
+ if (BLI_bvhtree_ray_cast(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata->raycast_callback, treedata) != -1)
{
- BVHTreeFromEditMesh *data = meshdata->userdata;
- BMVert *eve = BM_vert_at_index(data->em->bm, index);
- copy_v3_v3(r_no, eve->no);
- break;
+ hit.dist += len_diff;
+ hit.dist /= local_scale;
+ if (hit.dist <= *ray_depth) {
+ *ray_depth = hit.dist;
+ copy_v3_v3(r_loc, hit.co);
+
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
+
+ if (r_no) {
+ copy_v3_v3(r_no, hit.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+
+ retval = true;
+
+ if (r_index) {
+ *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
+ }
+ }
}
}
+
+ return retval;
}
-static void get_edge_verts(
- const BVHTreeFromMeshType *meshdata, const int index,
- const float *v_pair[2])
+static bool raycastEditMesh(
+ SnapObjectContext *sctx,
+ const float ray_start[3], const float ray_dir[3],
+ Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index,
+ /* read/write args */
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ ListBase *r_hit_list)
{
- switch (meshdata->type) {
- case SNAP_MESH:
- {
- BVHTreeFromMesh *data = meshdata->userdata;
+ bool retval = false;
+ if (em->bm->totface == 0) {
+ return retval;
+ }
- const MVert *vert = data->vert;
- const MEdge *edge = data->edge + index;
+ SnapObjectData_EditMesh *sod = NULL;
+ BVHTreeFromEditMesh *treedata = NULL;
- v_pair[0] = vert[edge->v1].co;
- v_pair[1] = vert[edge->v2].co;
- break;
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ sod = *sod_p;
+ }
+ else {
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_EDIT_MESH;
+ }
+
+ if (sod->bvh_trees[2] == NULL) {
+ sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ }
+ treedata = sod->bvh_trees[2];
+
+ if (treedata) {
+ if (treedata->tree == NULL) {
+ BLI_bitmap *elem_mask = NULL;
+ int looptri_num_active = -1;
+
+ if (sctx->callbacks.edit_mesh.test_face_fn) {
+ elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
+ looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
+ em->bm, elem_mask,
+ sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
+ }
+ bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, NULL);
+
+ if (elem_mask) {
+ MEM_freeN(elem_mask);
+ }
}
- case SNAP_EDIT_MESH:
+ if (treedata->tree == NULL) {
+ return retval;
+ }
+ }
+ else {
+ return retval;
+ }
+
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_normal_local[3], ray_start_local[3], len_diff = 0.0f;
+
+ invert_m4_m4(imat, obmat);
+ transpose_m3_m4(timat, imat);
+
+ copy_v3_v3(ray_normal_local, ray_dir);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+
+ 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!
+ */
+ if (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp) { /* do_ray_start_correction */
+ /* We *need* a reasonably valid len_diff in this case.
+ * Get the distance to bvhtree root */
+ if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) {
+ return retval;
+ }
+ /* You need to make sure that ray_start is really far away,
+ * because even in the Orthografic view, in some cases,
+ * the ray can start inside the object (see T50486) */
+ if (len_diff > 400.0f) {
+ /* 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_v3fl(ray_start_local, ray_normal_local, len_diff);
+ local_depth -= len_diff;
+ }
+ else len_diff = 0.0f;
+ }
+ if (r_hit_list) {
+ struct RayCastAll_Data data;
+
+ data.bvhdata = treedata;
+ data.raycast_callback = treedata->raycast_callback;
+ data.obmat = obmat;
+ data.timat = timat;
+ data.len_diff = len_diff;
+ data.local_scale = local_scale;
+ data.ob = ob;
+ data.ob_uuid = ob_index;
+ data.hit_list = r_hit_list;
+ data.retval = retval;
+
+ BLI_bvhtree_ray_cast_all(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
+
+ retval = data.retval;
+ }
+ else {
+ BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
+
+ if (BLI_bvhtree_ray_cast(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata->raycast_callback, treedata) != -1)
{
- BVHTreeFromEditMesh *data = meshdata->userdata;
- BMEdge *eed = BM_edge_at_index(data->em->bm, index);
+ hit.dist += len_diff;
+ hit.dist /= local_scale;
+ if (hit.dist <= *ray_depth) {
+ *ray_depth = hit.dist;
+ copy_v3_v3(r_loc, hit.co);
+
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
+
+ if (r_no) {
+ copy_v3_v3(r_no, hit.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
- v_pair[0] = eed->v1->co;
- v_pair[1] = eed->v2->co;
- break;
+ retval = true;
+
+ if (r_index) {
+ *r_index = hit.index;
+ }
+ }
}
}
+
+ return retval;
}
-#define V3_MUL_ELEM(a, b) \
- (a)[0] * (b)[0], \
- (a)[1] * (b)[1], \
- (a)[2] * (b)[2]
-static bool test_vert_dist(
- const float vco[3], const float ray_co[3], const float ray_dir[3],
- const float ray_depth_range[2], const float scale[3],
+/**
+ * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
+ *
+ * \note Duplicate args here are documented at #snapObjectsRay
+ */
+static bool raycastObj(
+ SnapObjectContext *sctx,
+ const float ray_start[3], const float ray_dir[3],
+ Object *ob, float obmat[4][4], const unsigned int ob_index,
+ bool use_obedit,
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *ray_depth,
/* return args */
- float r_co[3])
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4],
+ ListBase *r_hit_list)
{
- const float vco_sc[3] = {V3_MUL_ELEM(vco, scale)};
- const float origin_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
- const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)};
+ bool retval = false;
- float depth, dist_sq;
- dist_sq = dist_squared_to_ray_v3(origin_sc, dir_sc, vco_sc, &depth);
+ if (ob->type == OB_MESH) {
+ BMEditMesh *em;
- if (depth < ray_depth_range[0]) {
- return false;
+ if (use_obedit) {
+ em = BKE_editmesh_from_object(ob);
+ retval = raycastEditMesh(
+ sctx,
+ ray_start, ray_dir,
+ ob, em, obmat, ob_index,
+ ray_depth, r_loc, r_no, r_index, r_hit_list);
+ }
+ else {
+ /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
+ * still set the 'em' to NULL, since we only want the 'dm'. */
+ DerivedMesh *dm;
+ em = BKE_editmesh_from_object(ob);
+ if (em) {
+ editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm);
+ }
+ else {
+ dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
+ }
+ retval = raycastDerivedMesh(
+ sctx,
+ ray_start, ray_dir,
+ ob, dm, obmat, ob_index,
+ ray_depth, r_loc, r_no, r_index, r_hit_list);
+ }
}
- if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
- *dist_to_ray_sq = dist_sq;
+ if (retval) {
+ if (r_ob) {
+ *r_ob = ob;
+ copy_m4_m4(r_obmat, obmat);
+ }
+ }
- copy_v3_v3(r_co, vco);
+ return retval;
+}
- *ray_depth = depth;
- return true;
- }
- return false;
+
+struct RaycastObjUserData {
+ const float *ray_start;
+ const float *ray_dir;
+ unsigned int ob_index;
+ /* read/write args */
+ float *ray_depth;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ int *r_index;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ ListBase *r_hit_list;
+ bool ret;
+};
+
+static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data)
+{
+ struct RaycastObjUserData *dt = data;
+ dt->ret |= raycastObj(
+ sctx,
+ dt->ray_start, dt->ray_dir,
+ ob, obmat, dt->ob_index++, is_obedit,
+ dt->ray_depth,
+ dt->r_loc, dt->r_no, dt->r_index,
+ dt->r_ob, dt->r_obmat,
+ dt->r_hit_list);
}
-static bool test_edge_dist(
- 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],
+/**
+ * Main RayCast Function
+ * ======================
+ *
+ * Walks through all objects in the scene to find the `hit` on object surface.
+ *
+ * \param sctx: Snap context to store data.
+ * \param snapdata: struct generated in `set_snapdata`.
+ * \param snap_select : from enum SnapSelect.
+ * \param use_object_edit_cage : Uses the coordinates of BMesh(if any) to do the snapping.
+ * \param obj_list: List with objects to snap (created in `create_object_list`).
+ *
+ * Read/Write Args
+ * ---------------
+ *
+ * \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored.
+ *
+ * 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 raycastObjects(
+ SnapObjectContext *sctx,
+ const float ray_start[3], const float ray_dir[3],
+ const SnapSelect snap_select, const bool use_object_edit_cage,
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *ray_depth,
/* return args */
- float r_co[3])
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4],
+ ListBase *r_hit_list)
{
- const float v1_sc[3] = {V3_MUL_ELEM(v1, scale)};
- const float v2_sc[3] = {V3_MUL_ELEM(v2, scale)};
- const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
- const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)};
+ Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
- float tmp_co[3], depth, dist_sq;
- dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth);
+ struct RaycastObjUserData data = {
+ .ray_start = ray_start,
+ .ray_dir = ray_dir,
+ .ob_index = 0,
+ .ray_depth = ray_depth,
+ .r_loc = r_loc,
+ .r_no = r_no,
+ .r_index = r_index,
+ .r_ob = r_ob,
+ .r_obmat = r_obmat,
+ .r_hit_list = r_hit_list,
+ .ret = false,
+ };
- if (depth < ray_depth_range[0]) {
- return false;
- }
+ iter_snap_objects(sctx, snap_select, obedit, raycast_obj_cb, &data);
- if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
- *dist_to_ray_sq = dist_sq;
+ return data.ret;
+}
- tmp_co[0] /= scale[0];
- tmp_co[1] /= scale[1];
- tmp_co[2] /= scale[2];
- copy_v3_v3(r_co, tmp_co);
+/** \} */
- *ray_depth = depth;
- return true;
- }
- return false;
+
+/* -------------------------------------------------------------------- */
+
+/** Snap Nearest utilities
+ * \{ */
+
+static void copy_dm_vert_no(const int index, float r_no[3], const BVHTreeFromMesh *data)
+{
+ const MVert *vert = data->vert + index;
+
+ normal_short_to_float_v3(r_no, vert->no);
+}
+
+static void copy_bvert_no(const int index, float r_no[3], const BVHTreeFromEditMesh *data)
+{
+ BMVert *eve = BM_vert_at_index(data->em->bm, index);
+
+ copy_v3_v3(r_no, eve->no);
+}
+
+static void get_dm_edge_verts(const int index, const float *v_pair[2], const BVHTreeFromMesh *data)
+{
+ const MVert *vert = data->vert;
+ const MEdge *edge = data->edge + index;
+
+ v_pair[0] = vert[edge->v1].co;
+ v_pair[1] = vert[edge->v2].co;
}
-#undef V3_MUL_ELEM
+static void get_bedge_verts(const int index, const float *v_pair[2], const BVHTreeFromEditMesh *data)
+{
+ BMEdge *eed = BM_edge_at_index(data->em->bm, index);
+
+ v_pair[0] = eed->v1->co;
+ v_pair[1] = eed->v2->co;
+}
static bool test_projected_vert_dist(
- PreDefProject *projectdefs,
- const float co[3], const enum eViewProj view_proj,
- const float mval[2], const float depth_range[2],
- float r_co[3])
+ const float depth_range[2], const float mval[2], const float co[3],
+ float pmat[4][4], const float win_half[2], const bool is_persp,
+ float *dist_px_sq, float r_co[3])
{
float depth;
- float(*pmat)[4] = projectdefs->pmat;
- if (view_proj == VIEW_PROJ_PERSP) {
+ if (is_persp) {
depth = mul_project_m4_v3_zfac(pmat, co);
if (depth < depth_range[0] || depth > depth_range[1]) {
return false;
@@ -428,109 +906,106 @@ static bool test_projected_vert_dist(
(dot_m4_v3_row_y(pmat, co) + pmat[3][1]),
};
- if (view_proj == VIEW_PROJ_PERSP) {
+ if (is_persp) {
mul_v2_fl(co2d, 1 / depth);
}
co2d[0] += 1.0f;
co2d[1] += 1.0f;
- co2d[0] *= projectdefs->win_half[0];
- co2d[1] *= projectdefs->win_half[1];
+ co2d[0] *= win_half[0];
+ co2d[1] *= win_half[1];
const float dist_sq = len_squared_v2v2(mval, co2d);
- if (dist_sq < projectdefs->dist_px_sq) {
+ if (dist_sq < *dist_px_sq) {
copy_v3_v3(r_co, co);
- projectdefs->dist_px_sq = dist_sq;
+ *dist_px_sq = dist_sq;
return true;
}
return false;
}
static bool test_projected_edge_dist(
- PreDefProject *projectdefs,
- const float va[3], const float vb[3], const float ray_start[3], const float ray_normal[3],
- const enum eViewProj view_proj, const float mval[2], const float depth_range[2],
- float r_co[3])
+ const float depth_range[2], const float mval[2],
+ float pmat[4][4], const float win_half[2], const bool is_persp,
+ const float ray_start[3], const float ray_dir[3],
+ const float va[3], const float vb[3],
+ float *dist_px_sq, float r_co[3])
{
float tmp_co[3], depth;
- dist_squared_ray_to_seg_v3(ray_start, ray_normal, va, vb, tmp_co, &depth);
- return test_projected_vert_dist(projectdefs, tmp_co, view_proj, mval, depth_range, r_co);
+ dist_squared_ray_to_seg_v3(ray_start, ray_dir, va, vb, tmp_co, &depth);
+ return test_projected_vert_dist(depth_range, mval, tmp_co, pmat, win_half, is_persp, dist_px_sq, r_co);
}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
-/** \Walk DFS
- * \{ */
-typedef struct Object_Nearest2dPrecalc {
+typedef struct Nearest2dPrecalc {
float ray_origin_local[3];
float ray_direction_local[3];
float ray_inv_dir[3];
- PreDefProject projectdefs;
+ float ray_min_dist;
+ float pmat[4][4]; /* perspective matrix multiplied by object matrix */
+ bool is_persp;
+ float win_half[2];
+
float mval[2];
bool sign[3];
- bool r_axis_closest[3];
- float depth_range[2];
-
- void *userdata;
- int index;
- float co[3];
- float no[3];
-} Object_Nearest2dPrecalc;
+} Nearest2dPrecalc;
-
-static void nearest2d_precalc(
- Object_Nearest2dPrecalc *neasrest_precalc, const ARegion *ar,
- const float dist_px, float obmat[4][4],
- const float ray_origin_local[3], const float ray_direction_local[3],
- const float mval[2], const float depth_range[2])
+/**
+ * \param lpmat: Perspective matrix multiplied by object matrix
+ */
+static void dist_squared_to_projected_aabb_precalc(
+ struct Nearest2dPrecalc *neasrest_precalc,
+ float lpmat[4][4], bool is_persp, const float win_half[2],
+ const float ray_min_dist, const float mval[2],
+ const float ray_origin_local[3], const float ray_direction_local[3])
{
- precalc_project(&neasrest_precalc->projectdefs, ar, dist_px, obmat);
+ copy_m4_m4(neasrest_precalc->pmat, lpmat);
+ neasrest_precalc->is_persp = is_persp;
+ copy_v2_v2(neasrest_precalc->win_half, win_half);
+ neasrest_precalc->ray_min_dist = ray_min_dist;
+
copy_v3_v3(neasrest_precalc->ray_origin_local, ray_origin_local);
copy_v3_v3(neasrest_precalc->ray_direction_local, ray_direction_local);
copy_v2_v2(neasrest_precalc->mval, mval);
- copy_v2_v2(neasrest_precalc->depth_range, depth_range);
for (int i = 0; i < 3; i++) {
- neasrest_precalc->ray_inv_dir[i] =
+ neasrest_precalc->ray_inv_dir[i] =
(neasrest_precalc->ray_direction_local[i] != 0.0f) ?
(1.0f / neasrest_precalc->ray_direction_local[i]) : FLT_MAX;
neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f);
- neasrest_precalc->r_axis_closest[i] = true;
}
}
-static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data)
+/* Returns the distance from a 2d coordinate to a BoundBox (Projected) */
+static float dist_squared_to_projected_aabb(
+ struct Nearest2dPrecalc *data,
+ const float bbmin[3], const float bbmax[3],
+ bool r_axis_closest[3])
{
- Object_Nearest2dPrecalc *data = user_data;
float local_bvmin[3], local_bvmax[3];
if (data->sign[0]) {
- local_bvmin[0] = bounds[0].max;
- local_bvmax[0] = bounds[0].min;
+ local_bvmin[0] = bbmax[0];
+ local_bvmax[0] = bbmin[0];
}
else {
- local_bvmin[0] = bounds[0].min;
- local_bvmax[0] = bounds[0].max;
+ local_bvmin[0] = bbmin[0];
+ local_bvmax[0] = bbmax[0];
}
if (data->sign[1]) {
- local_bvmin[1] = bounds[1].max;
- local_bvmax[1] = bounds[1].min;
+ local_bvmin[1] = bbmax[1];
+ local_bvmax[1] = bbmin[1];
}
else {
- local_bvmin[1] = bounds[1].min;
- local_bvmax[1] = bounds[1].max;
+ local_bvmin[1] = bbmin[1];
+ local_bvmax[1] = bbmax[1];
}
if (data->sign[2]) {
- local_bvmin[2] = bounds[2].max;
- local_bvmax[2] = bounds[2].min;
+ local_bvmin[2] = bbmax[2];
+ local_bvmax[2] = bbmin[2];
}
else {
- local_bvmin[2] = bounds[2].min;
- local_bvmax[2] = bounds[2].max;
+ local_bvmin[2] = bbmin[2];
+ local_bvmax[2] = bbmax[2];
}
const float tmin[3] = {
@@ -543,7 +1018,9 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
(local_bvmax[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1],
(local_bvmax[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2],
};
+ /* `va` and `vb` are the coordinates of the AABB edge closest to the ray */
float va[3], vb[3];
+ /* `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB */
float rtmin, rtmax;
int main_axis;
@@ -551,61 +1028,57 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
rtmax = tmax[0];
va[0] = vb[0] = local_bvmax[0];
main_axis = 3;
- data->r_axis_closest[0] = data->sign[0];
+ r_axis_closest[0] = data->sign[0];
}
else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
rtmax = tmax[1];
va[1] = vb[1] = local_bvmax[1];
main_axis = 2;
- data->r_axis_closest[1] = data->sign[1];
+ r_axis_closest[1] = data->sign[1];
}
else {
rtmax = tmax[2];
va[2] = vb[2] = local_bvmax[2];
main_axis = 1;
- data->r_axis_closest[2] = data->sign[2];
+ r_axis_closest[2] = data->sign[2];
}
if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
rtmin = tmin[0];
va[0] = vb[0] = local_bvmin[0];
main_axis -= 3;
- data->r_axis_closest[0] = !data->sign[0];
+ r_axis_closest[0] = !data->sign[0];
}
else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
rtmin = tmin[1];
va[1] = vb[1] = local_bvmin[1];
main_axis -= 1;
- data->r_axis_closest[1] = !data->sign[1];
+ r_axis_closest[1] = !data->sign[1];
}
else {
rtmin = tmin[2];
va[2] = vb[2] = local_bvmin[2];
main_axis -= 2;
- data->r_axis_closest[2] = !data->sign[2];
+ r_axis_closest[2] = !data->sign[2];
}
if (main_axis < 0) {
main_axis += 3;
}
- /* if rtmin < rtmax, ray intersect `AABB` */
- if (rtmin <= rtmax) {
+#define IGNORE_BEHIND_RAY
#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_local[main_axis];
- data->r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj);
- return true;
- }
-#ifdef IGNORE_BEHIND_RAY
- /* `if rtmin < depth_min`, the whole `AABB` is behing us */
- else if (rtmin < min_depth) {
- return fallback;
+ float depth_max = depth_get(local_bvmax, data->ray_origin_local, data->ray_direction_local);
+ if (depth_max < data->ray_min_dist) {
+ return FLT_MAX;
}
#endif
+#undef IGNORE_BEHIND_RAY
+
+ /* if rtmin <= rtmax, ray intersect `AABB` */
+ if (rtmin <= rtmax) {
+ return 0;
+ }
+
if (data->sign[main_axis]) {
va[main_axis] = local_bvmax[main_axis];
vb[main_axis] = local_bvmin[main_axis];
@@ -616,110 +1089,172 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
}
float scale = fabsf(local_bvmax[main_axis] - local_bvmin[main_axis]);
- float (*pmat)[4] = data->projectdefs.pmat;
- float depth_a = mul_project_m4_v3_zfac(pmat, va);
- float depth_b = depth_a + pmat[main_axis][3] * scale;
+ float (*pmat)[4] = data->pmat;
float va2d[2] = {
(dot_m4_v3_row_x(pmat, va) + pmat[3][0]),
(dot_m4_v3_row_y(pmat, va) + pmat[3][1]),
};
float vb2d[2] = {
- (va2d[0] + pmat[main_axis][0] * scale) / depth_b,
- (va2d[1] + pmat[main_axis][1] * scale) / depth_b,
+ (va2d[0] + pmat[main_axis][0] * scale),
+ (va2d[1] + pmat[main_axis][1] * scale),
};
- va2d[0] /= depth_a;
- va2d[1] /= depth_a;
+ if (data->is_persp) {
+ float depth_a = mul_project_m4_v3_zfac(pmat, va);
+ float depth_b = depth_a + pmat[main_axis][3] * scale;
+ va2d[0] /= depth_a;
+ va2d[1] /= depth_a;
+ vb2d[0] /= depth_b;
+ vb2d[1] /= depth_b;
+ }
va2d[0] += 1.0f;
va2d[1] += 1.0f;
vb2d[0] += 1.0f;
vb2d[1] += 1.0f;
- va2d[0] *= data->projectdefs.win_half[0];
- va2d[1] *= data->projectdefs.win_half[1];
- vb2d[0] *= data->projectdefs.win_half[0];
- vb2d[1] *= data->projectdefs.win_half[1];
-
- //float dvec[2], edge[2], rdist;
- //sub_v2_v2v2(dvec, data->mval, va2d);
- //sub_v2_v2v2(edge, vb2d, va2d);
- float rdist;
- short dvec[2] = {data->mval[0] - va2d[0], data->mval[1] - va2d[1]};
- short edge[2] = {vb2d[0] - va2d[0], vb2d[1] - va2d[1]};
- float lambda = dvec[0] * edge[0] + dvec[1] * edge[1];
+ va2d[0] *= data->win_half[0];
+ va2d[1] *= data->win_half[1];
+ vb2d[0] *= data->win_half[0];
+ vb2d[1] *= data->win_half[1];
+
+ float dvec[2], edge[2], lambda, rdist;
+ sub_v2_v2v2(dvec, data->mval, va2d);
+ sub_v2_v2v2(edge, vb2d, va2d);
+ lambda = dot_v2v2(dvec, edge);
if (lambda != 0.0f) {
- lambda /= edge[0] * edge[0] + edge[1] * edge[1];
+ lambda /= len_squared_v2(edge);
if (lambda <= 0.0f) {
rdist = len_squared_v2v2(data->mval, va2d);
- data->r_axis_closest[main_axis] = true;
+ r_axis_closest[main_axis] = true;
}
else if (lambda >= 1.0f) {
rdist = len_squared_v2v2(data->mval, vb2d);
- data->r_axis_closest[main_axis] = false;
+ r_axis_closest[main_axis] = false;
}
else {
va2d[0] += edge[0] * lambda;
va2d[1] += edge[1] * lambda;
rdist = len_squared_v2v2(data->mval, va2d);
- data->r_axis_closest[main_axis] = lambda < 0.5f;
+ r_axis_closest[main_axis] = lambda < 0.5f;
}
}
else {
rdist = len_squared_v2v2(data->mval, va2d);
}
- return rdist < data->projectdefs.dist_px_sq;
+ return rdist;
+}
+
+static float dist_squared_to_projected_aabb_simple(
+ float lpmat[4][4], const float win_half[2],
+ const float ray_min_dist, const float mval[2],
+ const float ray_origin_local[3], const float ray_direction_local[3],
+ const float bbmin[3], const float bbmax[3])
+{
+ struct Nearest2dPrecalc data;
+ dist_squared_to_projected_aabb_precalc(
+ &data, lpmat, true, win_half, ray_min_dist,
+ mval, ray_origin_local, ray_direction_local);
+
+ bool dummy[3] = {true, true, true};
+ return dist_squared_to_projected_aabb(&data, bbmin, bbmax, dummy);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** Walk DFS
+ * \{ */
+
+typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, const float *v_pair[2], void *data);
+typedef void (*Nearest2DCopyVertNoCallback)(const int index, float r_no[3], void *data);
+
+typedef struct Nearest2dUserData {
+ struct Nearest2dPrecalc data_precalc;
+
+ float dist_px_sq;
+
+ bool r_axis_closest[3];
+
+ float depth_range[2];
+
+ void *userdata;
+ Nearest2DGetEdgeVertsCallback get_edge_verts;
+ Nearest2DCopyVertNoCallback copy_vert_no;
+
+ int index;
+ float co[3];
+ float no[3];
+} Nearest2dUserData;
+
+
+static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data)
+{
+ Nearest2dUserData *data = user_data;
+ const float bbmin[3] = {bounds[0].min, bounds[1].min, bounds[2].min};
+ const float bbmax[3] = {bounds[0].max, bounds[1].max, bounds[2].max};
+ const float rdist = dist_squared_to_projected_aabb(
+ &data->data_precalc, bbmin, bbmax, data->r_axis_closest);
+ return rdist < data->dist_px_sq;
}
static bool cb_walk_leaf_snap_vert(const BVHTreeAxisRange *bounds, int index, void *userdata)
{
- struct Object_Nearest2dPrecalc *neasrest_precalc = userdata;
+ struct Nearest2dUserData *data = userdata;
+ struct Nearest2dPrecalc *neasrest_precalc = &data->data_precalc;
const float co[3] = {
(bounds[0].min + bounds[0].max) / 2,
(bounds[1].min + bounds[1].max) / 2,
(bounds[2].min + bounds[2].max) / 2,
};
- /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP)
- * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO),
- * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/
if (test_projected_vert_dist(
- &neasrest_precalc->projectdefs, co, VIEW_PROJ_PERSP,
- neasrest_precalc->mval, neasrest_precalc->depth_range,
- neasrest_precalc->co))
+ data->depth_range,
+ neasrest_precalc->mval, co,
+ neasrest_precalc->pmat,
+ neasrest_precalc->win_half,
+ neasrest_precalc->is_persp,
+ &data->dist_px_sq,
+ data->co))
{
- copy_vert_no(neasrest_precalc->userdata, index, neasrest_precalc->no);
- neasrest_precalc->index = index;
+ data->copy_vert_no(index, data->no, data->userdata);
+ data->index = index;
}
return true;
}
static bool cb_walk_leaf_snap_edge(const BVHTreeAxisRange *UNUSED(bounds), int index, void *userdata)
{
- struct Object_Nearest2dPrecalc *neasrest_precalc = userdata;
+ struct Nearest2dUserData *data = userdata;
+ struct Nearest2dPrecalc *neasrest_precalc = &data->data_precalc;
const float *v_pair[2];
- get_edge_verts(neasrest_precalc->userdata, index, v_pair);
+ data->get_edge_verts(index, v_pair, data->userdata);
- /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP)
- * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO),
- * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/
if (test_projected_edge_dist(
- &neasrest_precalc->projectdefs, v_pair[0], v_pair[1],
- neasrest_precalc->ray_origin_local, neasrest_precalc->ray_direction_local,
- VIEW_PROJ_PERSP, neasrest_precalc->mval, neasrest_precalc->depth_range,
- neasrest_precalc->co))
+ data->depth_range,
+ neasrest_precalc->mval,
+ neasrest_precalc->pmat,
+ neasrest_precalc->win_half,
+ neasrest_precalc->is_persp,
+ neasrest_precalc->ray_origin_local,
+ neasrest_precalc->ray_direction_local,
+ v_pair[0], v_pair[1],
+ &data->dist_px_sq,
+ data->co))
{
- sub_v3_v3v3(neasrest_precalc->no, v_pair[0], v_pair[1]);
- neasrest_precalc->index = index;
+ sub_v3_v3v3(data->no, v_pair[0], v_pair[1]);
+ data->index = index;
}
return true;
}
static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char axis, void *userdata)
{
- const bool *r_axis_closest = ((struct Object_Nearest2dPrecalc *)userdata)->r_axis_closest;
+ const bool *r_axis_closest = ((struct Nearest2dUserData *)userdata)->r_axis_closest;
return r_axis_closest[axis];
}
@@ -731,46 +1266,56 @@ static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char a
* \{ */
static bool snapArmature(
- const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
- const short snap_to, const float origin[3], const float dir[3],
- const float mval[2], const enum eViewProj view_proj, const float depth_range[2],
+ SnapData *snapdata,
+ Object *ob, bArmature *arm, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
bool retval = false;
- float ray_start_local[3], ray_normal_local[3];
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ float ray_start_local[3], ray_normal_local[3]; /* Used only in the snap to edges */
+ if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
float imat[4][4];
invert_m4_m4(imat, obmat);
- copy_v3_v3(ray_start_local, origin);
- copy_v3_v3(ray_normal_local, dir);
+ copy_v3_v3(ray_start_local, snapdata->ray_origin);
+ copy_v3_v3(ray_normal_local, snapdata->ray_dir);
mul_m4_v3(imat, ray_start_local);
mul_mat3_m4_v3(imat, ray_normal_local);
}
+ else if (snapdata->snap_to != SCE_SNAP_MODE_VERTEX) { /* Currently only edge and vert */
+ return retval;
+ }
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, obmat);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float lpmat[4][4], dist_px_sq;
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ dist_px_sq = SQUARE(*dist_px);
if (arm->edbo) {
for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) {
if (eBone->layer & arm->layer) {
/* skip hidden or moving (selected) bones */
if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
retval |= test_projected_vert_dist(
- &projectdefs, eBone->head, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, eBone->head,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
retval |= test_projected_vert_dist(
- &projectdefs, eBone->tail, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, eBone->tail,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
break;
case SCE_SNAP_MODE_EDGE:
retval |= test_projected_edge_dist(
- &projectdefs, eBone->head, eBone->tail, ray_start_local, ray_normal_local,
- view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, lpmat,
+ snapdata->win_half, is_persp, ray_start_local, ray_normal_local,
+ eBone->head, eBone->tail,
+ &dist_px_sq, r_loc);
break;
}
}
@@ -785,52 +1330,60 @@ static bool snapArmature(
const float *head_vec = pchan->pose_head;
const float *tail_vec = pchan->pose_tail;
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
retval |= test_projected_vert_dist(
- &projectdefs, head_vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, head_vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
retval |= test_projected_vert_dist(
- &projectdefs, tail_vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, tail_vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
break;
case SCE_SNAP_MODE_EDGE:
retval |= test_projected_edge_dist(
- &projectdefs, head_vec, tail_vec, ray_start_local, ray_normal_local,
- view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, lpmat,
+ snapdata->win_half, is_persp, ray_start_local, ray_normal_local,
+ head_vec, tail_vec,
+ &dist_px_sq, r_loc);
break;
}
}
}
}
if (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *dist_px = sqrtf(dist_px_sq);
mul_m4_v3(obmat, r_loc);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
return true;
}
return false;
}
static bool snapCurve(
- const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float depth_range[2],
+ SnapData *snapdata,
+ Object *ob, Curve *cu, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
bool retval = false;
/* only vertex snapping mode (eg control points and handles) supported for now) */
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ if (snapdata->snap_to != SCE_SNAP_MODE_VERTEX) {
return retval;
}
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, obmat);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float lpmat[4][4], dist_px_sq;
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ dist_px_sq = SQUARE(*dist_px);
for (Nurb *nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
for (int u = 0; u < nu->pntsu; u++) {
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
if (ob->mode == OB_MODE_EDIT) {
@@ -840,19 +1393,25 @@ static bool snapCurve(
break;
}
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[1],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
/* 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 |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[0], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[0],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
if (!(nu->bezt[u].f3 & SELECT) &&
!(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
{
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[2], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[2],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
else {
@@ -861,7 +1420,9 @@ static bool snapCurve(
break;
}
retval |= test_projected_vert_dist(
- &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bp[u].vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
else {
@@ -869,11 +1430,15 @@ static bool snapCurve(
if (nu->pntsu > 1) {
if (nu->bezt) {
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[1],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
else {
retval |= test_projected_vert_dist(
- &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bp[u].vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
}
@@ -885,8 +1450,9 @@ static bool snapCurve(
}
}
if (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *dist_px = sqrtf(dist_px_sq);
mul_m4_v3(obmat, r_loc);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
return true;
}
return false;
@@ -894,11 +1460,10 @@ static bool snapCurve(
/* may extend later (for now just snaps to empty center) */
static bool snapEmpty(
- const ARegion *ar, Object *ob, float obmat[4][4],
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float depth_range[2],
+ SnapData *snapdata,
+ Object *ob, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
@@ -909,15 +1474,20 @@ static bool snapEmpty(
}
/* for now only vertex supported */
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, NULL);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float dist_px_sq = SQUARE(*dist_px);
float tmp_co[3];
copy_v3_v3(tmp_co, obmat[3]);
- if (test_projected_vert_dist(&projectdefs, tmp_co, view_proj, mval, depth_range, r_loc)) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ if (test_projected_vert_dist(
+ snapdata->depth_range, snapdata->mval, tmp_co,
+ snapdata->pmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc))
+ {
+ *dist_px = sqrtf(dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
retval = true;
}
break;
@@ -930,18 +1500,17 @@ static bool snapEmpty(
}
static bool snapCamera(
- const SnapObjectContext *sctx, Object *object, float obmat[4][4],
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float depth_range[2],
+ const SnapObjectContext *sctx, SnapData *snapdata,
+ Object *object, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
Scene *scene = sctx->scene;
- PreDefProject projectdefs;
- precalc_project(&projectdefs, sctx->v3d_data.ar, *dist_px, NULL);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float dist_px_sq = SQUARE(*dist_px);
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
bool retval = false;
@@ -962,7 +1531,7 @@ static bool snapCamera(
invert_m4_m4(orig_camera_imat, orig_camera_mat);
invert_m4_m4(imat, obmat);
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
MovieTrackingObject *tracking_object;
@@ -1002,7 +1571,9 @@ static bool snapCamera(
mul_m4_v3(vertex_obmat, bundle_pos);
retval |= test_projected_vert_dist(
- &projectdefs, bundle_pos, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, bundle_pos,
+ snapdata->pmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
@@ -1013,7 +1584,8 @@ static bool snapCamera(
}
if (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *dist_px = sqrtf(dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
return true;
}
return false;
@@ -1025,71 +1597,17 @@ 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;
- const float *depth_range;
- float *ray_depth;
-};
-
-static void test_vert_ray_dist_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 struct BVHTreeFromMeshType *data = ndata->bvhdata;
-
- const float *co = get_vert_co(data, index);
-
- if (test_vert_dist(
- co, origin, dir, ndata->depth_range,
- scale, ndata->ray_depth, &nearest->dist_sq,
- nearest->co))
- {
- copy_vert_no(data, index, nearest->no);
- nearest->index = index;
- }
-}
-
-static void test_edge_ray_dist_cb(
- void *userdata, const float origin[3], const float dir[3],
- const float scale[3], int index, BVHTreeNearest *nearest)
-{
- struct NearestDM_Data *ndata = userdata;
- BVHTreeFromMeshType *data = ndata->bvhdata;
-
- const float *v_pair[2];
- get_edge_verts(data, index, v_pair);
-
- if (test_edge_dist(
- v_pair[0], v_pair[1], origin, dir, ndata->depth_range,
- scale, ndata->ray_depth, &nearest->dist_sq,
- nearest->co))
- {
- sub_v3_v3v3(nearest->no, v_pair[0], v_pair[1]);
- nearest->index = index;
- }
-}
-
static bool snapDerivedMesh(
- SnapObjectContext *sctx,
- Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
- const short snap_to, const float mval[2], const enum eViewProj view_proj, bool do_bb,
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
- const float depth_range[2],
+ SnapObjectContext *sctx, SnapData *snapdata,
+ Object *ob, DerivedMesh *dm, float obmat[4][4],
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
- float r_loc[3], float r_no[3], int *r_index,
- ListBase *r_hit_list)
+ float r_loc[3], float r_no[3])
{
bool retval = false;
- if (snap_to == SCE_SNAP_MODE_FACE) {
- if (dm->getNumPolys(dm) == 0) {
- return retval;
- }
- }
- else if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
if (dm->getNumEdges(dm) == 0) {
return retval;
}
@@ -1100,106 +1618,89 @@ static bool snapDerivedMesh(
}
}
- {
- bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && (view_proj == VIEW_PROJ_ORTHO);
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_normal_local[3];
+ float local_scale;
- float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_start_local[3], ray_normal_local[3];
- float local_scale, local_depth, len_diff;
+ invert_m4_m4(imat, obmat);
+ transpose_m3_m4(timat, imat);
- invert_m4_m4(imat, obmat);
- transpose_m3_m4(timat, imat);
+ copy_v3_v3(ray_normal_local, snapdata->ray_dir);
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
+ mul_mat3_m4_v3(imat, ray_normal_local);
- 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 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;
- }
+ float lpmat[4][4];
+ float ray_org_local[3];
+ float ray_min_dist;
- if (do_bb) {
- BoundBox *bb = BKE_object_boundbox_get(ob);
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ ray_min_dist = snapdata->depth_range[0] * local_scale;
- if (bb) {
- BoundBox bb_temp;
+ copy_v3_v3(ray_org_local, snapdata->ray_origin);
+ mul_m4_v3(imat, ray_org_local);
- /* 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);
+ /* Test BoundBox */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ if (bb) {
+ /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see: T46099, T46816 */
+ float dist_px_sq = dist_squared_to_projected_aabb_simple(
+ lpmat, snapdata->win_half, ray_min_dist, snapdata->mval,
+ ray_org_local, ray_normal_local, bb->vec[0], bb->vec[6]);
+ if (dist_px_sq > SQUARE(*dist_px)) {
+ return retval;
+ }
+ }
- /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'dist_px'),
- * scale up so we can snap against verts & edges on the boundbox, see T46816. */
- if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
- BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f);
- bb = &bb_temp;
- }
+ SnapObjectData_Mesh *sod = NULL;
+ BVHTreeFromMesh *treedata = NULL;
- /* was local_depth, see: T47838 */
- len_diff = BVH_RAYCAST_DIST_MAX;
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ sod = *sod_p;
+ }
+ else {
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_MESH;
+ }
- if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
- return retval;
- }
- need_ray_start_correction_init = false;
- }
+ int tree_index = -1;
+ switch (snapdata->snap_to) {
+ case SCE_SNAP_MODE_EDGE:
+ tree_index = 1;
+ break;
+ case SCE_SNAP_MODE_VERTEX:
+ tree_index = 0;
+ break;
+ }
+ if (tree_index != -1) {
+ if (sod->bvh_trees[tree_index] == NULL) {
+ sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
}
+ treedata = sod->bvh_trees[tree_index];
- SnapObjectData_Mesh *sod = NULL;
- BVHTreeFromMesh *treedata = NULL, treedata_stack;
-
- if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
- void **sod_p;
- if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
- sod = *sod_p;
+ /* the tree is owned by the DM and may have been freed since we last used! */
+ if (treedata && treedata->tree) {
+ if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
+ free_bvhtree_from_mesh(treedata);
}
else {
- sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
- sod->sd.type = SNAP_MESH;
- }
-
- int tree_index = -1;
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- tree_index = 2;
- break;
- case SCE_SNAP_MODE_EDGE:
- tree_index = 1;
- break;
- case SCE_SNAP_MODE_VERTEX:
- tree_index = 0;
- break;
- }
- if (tree_index != -1) {
- if (sod->bvh_trees[tree_index] == NULL) {
- sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ if (treedata->vert == NULL) {
+ treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated);
}
- treedata = sod->bvh_trees[tree_index];
-
- /* the tree is owned by the DM and may have been freed since we last used! */
- if (treedata && treedata->tree) {
- if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
- free_bvhtree_from_mesh(treedata);
- }
+ if ((tree_index == 1) && (treedata->edge == NULL)) {
+ treedata->edge = DM_get_edge_array(dm, &treedata->edge_allocated);
}
}
}
- else {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
- }
+ }
- if (treedata && treedata->tree == NULL) {
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
- break;
+ if (treedata) {
+ if (treedata->tree == NULL) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_EDGE:
bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6);
break;
@@ -1208,207 +1709,70 @@ static bool snapDerivedMesh(
break;
}
}
-
- if (!treedata || !treedata->tree) {
+ if (treedata->tree == NULL) {
return retval;
}
+ }
+ else {
+ return retval;
+ }
- if (snap_to == SCE_SNAP_MODE_FACE) {
- /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
- * been *inside* boundbox, leading to snap failures (see T38409).
- * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
- */
- if (view_proj == VIEW_PROJ_ORTHO) { /* 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.
- */
- 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 + depth_range[0] * local_scale);
- local_depth -= len_diff;
- }
- else {
- len_diff = 0.0f;
- }
- if (r_hit_list) {
- struct RayCastAll_Data data;
-
- data.bvhdata = treedata;
- data.raycast_callback = treedata->raycast_callback;
- data.obmat = obmat;
- data.timat = timat;
- data.len_diff = len_diff;
- data.local_scale = local_scale;
- data.ob = ob;
- data.ob_uuid = ob_index;
- data.hit_list = r_hit_list;
- data.retval = retval;
-
- BLI_bvhtree_ray_cast_all(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- *ray_depth, raycast_all_cb, &data);
-
- retval = data.retval;
- }
- else {
- BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
-
- if (BLI_bvhtree_ray_cast(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- &hit, treedata->raycast_callback, treedata) != -1)
- {
- hit.dist += len_diff;
- hit.dist /= local_scale;
- if (hit.dist <= *ray_depth) {
- *ray_depth = hit.dist;
- copy_v3_v3(r_loc, hit.co);
-
- /* back to worldspace */
- mul_m4_v3(obmat, r_loc);
-
- if (r_no) {
- copy_v3_v3(r_no, hit.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
-
- retval = true;
-
- if (r_index) {
- *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
- }
- }
- }
- }
- }
- /* SCE_SNAP_MODE_VERTEX or SCE_SNAP_MODE_EDGE */
- else {
- const ARegion *ar = sctx->v3d_data.ar;
-
- float ray_org_local[3];
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_MESH};
-
- if (view_proj == VIEW_PROJ_PERSP) {
- Object_Nearest2dPrecalc neasrest_precalc;
- neasrest_precalc.userdata = &treedata_type;
- neasrest_precalc.index = -1;
-
- nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat,
- ray_org_local, ray_normal_local, mval, depth_range);
-
- BVHTree_WalkLeafCallback cb_walk_leaf =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
-
- BLI_bvhtree_walk_dfs(
- treedata->tree,
- cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc);
-
- if (neasrest_precalc.index != -1) {
- copy_v3_v3(r_loc, neasrest_precalc.co);
- mul_m4_v3(obmat, r_loc);
- if (r_no) {
- copy_v3_v3(r_no, neasrest_precalc.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
- *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq);
-
- retval = true;
- }
- }
- else {
- BVHTreeNearest nearest;
-
- nearest.index = -1;
- float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px);
- nearest.dist_sq = SQUARE(dist_3d);
-
-
- float ob_scale[3];
- mat4_to_size(ob_scale, obmat);
-
- struct NearestDM_Data userdata;
- userdata.bvhdata = &treedata_type;
- userdata.depth_range = depth_range;
- userdata.ray_depth = ray_depth;
-
- BVHTree_NearestToRayCallback cb_test_ray_dist =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- test_vert_ray_dist_cb : test_edge_ray_dist_cb;
-
- if (BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_org_local, ray_normal_local,
- true, ob_scale, &nearest, cb_test_ray_dist, &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 *= sqrtf(nearest.dist_sq) / dist_3d;
-
- retval = true;
- }
- }
+ /* Warning: the depth_max is currently being used only in perspective view.
+ * It is not correct to limit the maximum depth for elements obtained with nearest
+ * since this limitation depends on the normal and the size of the occlusion face.
+ * And more... ray_depth is being confused with Z-depth here... (varies only the precision) */
+ const float ray_depth_max_global = *ray_depth + snapdata->depth_range[0];
+
+ Nearest2dUserData neasrest2d = {
+ .dist_px_sq = SQUARE(*dist_px),
+ .r_axis_closest = {1.0f, 1.0f, 1.0f},
+ .depth_range = {snapdata->depth_range[0], ray_depth_max_global},
+ .userdata = treedata,
+ .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_dm_edge_verts,
+ .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_dm_vert_no,
+ .index = -1};
+
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest2d.data_precalc, lpmat,
+ snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half,
+ ray_min_dist, snapdata->mval, ray_org_local, ray_normal_local);
+
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d);
+
+ if (neasrest2d.index != -1) {
+ copy_v3_v3(r_loc, neasrest2d.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest2d.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
}
+ *dist_px = sqrtf(neasrest2d.dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
- if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
- if (treedata) {
- free_bvhtree_from_mesh(treedata);
- }
- }
+ retval = true;
}
return retval;
}
static bool snapEditMesh(
- SnapObjectContext *sctx,
- Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index,
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
- const float depth_range[2],
+ SnapObjectContext *sctx, SnapData *snapdata,
+ Object *ob, BMEditMesh *em, float obmat[4][4],
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
- float r_loc[3], float r_no[3], int *r_index,
- ListBase *r_hit_list)
+ float r_loc[3], float r_no[3])
{
bool retval = false;
- if (snap_to == SCE_SNAP_MODE_FACE) {
- if (em->bm->totface == 0) {
- return retval;
- }
- }
- if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
if (em->bm->totedge == 0) {
return retval;
}
@@ -1419,293 +1783,132 @@ static bool snapEditMesh(
}
}
- {
- float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_normal_local[3];
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_normal_local[3];
- invert_m4_m4(imat, obmat);
- transpose_m3_m4(timat, imat);
+ invert_m4_m4(imat, obmat);
+ transpose_m3_m4(timat, imat);
- copy_v3_v3(ray_normal_local, ray_normal);
+ copy_v3_v3(ray_normal_local, snapdata->ray_dir);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
- SnapObjectData_EditMesh *sod = NULL;
+ /* local scale in normal direction */
+ float local_scale = normalize_v3(ray_normal_local);
- BVHTreeFromEditMesh *treedata = NULL, treedata_stack;
+ SnapObjectData_EditMesh *sod = NULL;
+ BVHTreeFromEditMesh *treedata = NULL;
- if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
- void **sod_p;
- if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
- sod = *sod_p;
- }
- else {
- sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
- sod->sd.type = SNAP_EDIT_MESH;
- }
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ sod = *sod_p;
+ }
+ else {
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_EDIT_MESH;
+ }
- int tree_index = -1;
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- tree_index = 2;
- break;
- case SCE_SNAP_MODE_EDGE:
- tree_index = 1;
- break;
- case SCE_SNAP_MODE_VERTEX:
- tree_index = 0;
- break;
- }
- if (tree_index != -1) {
- if (sod->bvh_trees[tree_index] == NULL) {
- sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
- }
- treedata = sod->bvh_trees[tree_index];
- }
- }
- else {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
+ int tree_index = -1;
+ switch (snapdata->snap_to) {
+ case SCE_SNAP_MODE_EDGE:
+ tree_index = 1;
+ break;
+ case SCE_SNAP_MODE_VERTEX:
+ tree_index = 0;
+ break;
+ }
+ if (tree_index != -1) {
+ if (sod->bvh_trees[tree_index] == NULL) {
+ sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
}
+ treedata = sod->bvh_trees[tree_index];
+ }
- if (treedata && treedata->tree == NULL) {
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- {
- BLI_bitmap *looptri_mask = NULL;
- int looptri_num_active = -1;
- if (sctx->callbacks.edit_mesh.test_face_fn) {
- looptri_mask = BLI_BITMAP_NEW(em->tottri, __func__);
- looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
- em->bm, looptri_mask,
- sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
- }
- bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6, NULL);
- if (looptri_mask) {
- MEM_freeN(looptri_mask);
- }
- break;
- }
+ if (treedata) {
+ if (treedata->tree == NULL) {
+ BLI_bitmap *elem_mask = NULL;
+ switch (snapdata->snap_to) {
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__);
+ elem_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,
+ BM_EDGES_OF_MESH, em->bm, elem_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);
- }
+ bvhtree_from_editmesh_edges_ex(treedata, em, elem_mask, edges_num_active, 0.0f, 2, 6);
break;
}
case SCE_SNAP_MODE_VERTEX:
{
- BLI_bitmap *verts_mask = NULL;
int verts_num_active = -1;
if (sctx->callbacks.edit_mesh.test_vert_fn) {
- verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
+ elem_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
verts_num_active = BM_iter_mesh_bitmap_from_filter(
- BM_VERTS_OF_MESH, em->bm, verts_mask,
+ BM_VERTS_OF_MESH, em->bm, elem_mask,
(bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn,
sctx->callbacks.edit_mesh.user_data);
}
- bvhtree_from_editmesh_verts_ex(treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6);
- if (verts_mask) {
- MEM_freeN(verts_mask);
- }
+ bvhtree_from_editmesh_verts_ex(treedata, em, elem_mask, verts_num_active, 0.0f, 2, 6);
break;
}
}
+ if (elem_mask) {
+ MEM_freeN(elem_mask);
+ }
}
-
- if (!treedata || !treedata->tree) {
+ if (treedata->tree == NULL) {
return retval;
}
+ }
+ else {
+ return retval;
+ }
- if (snap_to == SCE_SNAP_MODE_FACE) {
- float ray_start_local[3];
- copy_v3_v3(ray_start_local, ray_start);
- mul_m4_v3(imat, ray_start_local);
-
- /* 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 (view_proj == VIEW_PROJ_ORTHO) { /* 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.
- */
- 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 + depth_range[0] * local_scale);
- local_depth -= len_diff;
- }
- }
- if (r_hit_list) {
- struct RayCastAll_Data data;
-
- data.bvhdata = treedata;
- data.raycast_callback = treedata->raycast_callback;
- data.obmat = obmat;
- data.timat = timat;
- data.len_diff = len_diff;
- data.local_scale = local_scale;
- data.ob = ob;
- data.ob_uuid = ob_index;
- data.hit_list = r_hit_list;
- data.retval = retval;
-
- BLI_bvhtree_ray_cast_all(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- *ray_depth, raycast_all_cb, &data);
-
- retval = data.retval;
- }
- else {
- BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
-
- if (BLI_bvhtree_ray_cast(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- &hit, treedata->raycast_callback, treedata) != -1)
- {
- hit.dist += len_diff;
- hit.dist /= local_scale;
- if (hit.dist <= *ray_depth) {
- *ray_depth = hit.dist;
- copy_v3_v3(r_loc, hit.co);
-
- /* back to worldspace */
- mul_m4_v3(obmat, r_loc);
-
- if (r_no) {
- copy_v3_v3(r_no, hit.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
-
- retval = true;
-
- if (r_index) {
- *r_index = hit.index;
- }
- }
- }
- }
- }
- else {
- const ARegion *ar = sctx->v3d_data.ar;
-
- float ray_org_local[3];
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_EDIT_MESH};
-
- if (view_proj == VIEW_PROJ_PERSP) {
- Object_Nearest2dPrecalc neasrest_precalc;
- neasrest_precalc.userdata = &treedata_type;
- neasrest_precalc.index = -1;
-
- nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat,
- ray_org_local, ray_normal_local, mval, depth_range);
-
- BVHTree_WalkLeafCallback cb_walk_leaf =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
-
- BLI_bvhtree_walk_dfs(
- treedata->tree,
- cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc);
-
- if (neasrest_precalc.index != -1) {
- copy_v3_v3(r_loc, neasrest_precalc.co);
- mul_m4_v3(obmat, r_loc);
- if (r_no) {
- copy_v3_v3(r_no, neasrest_precalc.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
- *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq);
-
- retval = true;
- }
- }
- else {
- BVHTreeNearest nearest;
-
- nearest.index = -1;
- float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px);
- nearest.dist_sq = SQUARE(dist_3d);
-
-
- float ob_scale[3];
- mat4_to_size(ob_scale, obmat);
-
- struct NearestDM_Data userdata;
- userdata.bvhdata = &treedata_type;
- userdata.depth_range = depth_range;
- userdata.ray_depth = ray_depth;
-
- BVHTree_NearestToRayCallback cb_test_ray_dist =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- test_vert_ray_dist_cb : test_edge_ray_dist_cb;
-
- if (BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_org_local, ray_normal_local,
- false, ob_scale, &nearest, cb_test_ray_dist, &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 *= sqrtf(nearest.dist_sq) / dist_3d;
-
- retval = true;
- }
- }
+ float ray_org_local[3];
+ copy_v3_v3(ray_org_local, snapdata->ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ Nearest2dUserData neasrest2d = {
+ .dist_px_sq = SQUARE(*dist_px),
+ .r_axis_closest = {1.0f, 1.0f, 1.0f},
+ .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]},
+ .userdata = treedata,
+ .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_bedge_verts,
+ .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_bvert_no,
+ .index = -1};
+
+ float lpmat[4][4];
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest2d.data_precalc, lpmat,
+ snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half,
+ (snapdata->depth_range[0] * local_scale), snapdata->mval,
+ ray_org_local, ray_normal_local);
+
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d);
+
+ if (neasrest2d.index != -1) {
+ copy_v3_v3(r_loc, neasrest2d.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest2d.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
}
+ *dist_px = sqrtf(neasrest2d.dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
- if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
- if (treedata) {
- free_bvhtree_from_editmesh(treedata);
- }
- }
+ retval = true;
}
return retval;
@@ -1717,24 +1920,15 @@ static bool snapEditMesh(
* \note Duplicate args here are documented at #snapObjectsRay
*/
static bool snapObject(
- SnapObjectContext *sctx,
- 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 depth_range[2],
+ SnapObjectContext *sctx, SnapData *snapdata,
+ Object *ob, float obmat[4][4],
+ bool use_obedit,
/* read/write args */
float *ray_depth, 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)
+ float r_loc[3], float r_no[3],
+ Object **r_ob, float r_obmat[4][4])
{
- const enum eViewProj view_proj =
- ((sctx->use_v3d == false) || (mval == NULL)) ? VIEW_PROJ_NONE :
- (((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO);
-
- const ARegion *ar = sctx->v3d_data.ar;
-
bool retval = false;
if (ob->type == OB_MESH) {
@@ -1743,12 +1937,9 @@ static bool snapObject(
if (use_obedit) {
em = BKE_editmesh_from_object(ob);
retval = snapEditMesh(
- sctx, ob, em, obmat, ob_index,
- snap_to, mval, view_proj,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob, em, obmat,
ray_depth, dist_px,
- r_loc, r_no, r_index,
- r_hit_list);
+ r_loc, r_no);
}
else {
/* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
@@ -1762,42 +1953,39 @@ static bool snapObject(
dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
}
retval = snapDerivedMesh(
- sctx, ob, dm, obmat, ob_index,
- snap_to, mval, view_proj, true,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob, dm, obmat,
ray_depth, dist_px,
- r_loc, r_no,
- r_index, r_hit_list);
+ r_loc, r_no);
dm->release(dm);
}
}
- else if (snap_to != SCE_SNAP_MODE_FACE) {
+ else if (snapdata->snap_to != SCE_SNAP_MODE_FACE) {
if (ob->type == OB_ARMATURE) {
retval = snapArmature(
- ar, ob, ob->data, obmat, snap_to, ray_origin, ray_normal,
- mval, view_proj, depth_range, dist_px,
+ snapdata,
+ ob, ob->data, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_CURVE) {
retval = snapCurve(
- ar, ob, ob->data, obmat, snap_to, mval, view_proj,
- depth_range,
- dist_px,
+ snapdata,
+ ob, ob->data, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_EMPTY) {
retval = snapEmpty(
- ar, ob, obmat, snap_to, mval, view_proj,
- depth_range,
- dist_px,
+ snapdata,
+ ob, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_CAMERA) {
retval = snapCamera(
- sctx, ob, obmat, snap_to, mval, view_proj,
- depth_range,
- dist_px,
+ sctx, snapdata, ob, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
}
@@ -1812,6 +2000,34 @@ static bool snapObject(
return retval;
}
+
+struct SnapObjUserData {
+ SnapData *snapdata;
+ /* read/write args */
+ float *ray_depth;
+ float *dist_px;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ bool ret;
+};
+
+static void sanp_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data)
+{
+ struct SnapObjUserData *dt = data;
+ dt->ret |= snapObject(
+ sctx, dt->snapdata,
+ ob, obmat, is_obedit,
+ /* read/write args */
+ dt->ray_depth, dt->dist_px,
+ /* return args */
+ dt->r_loc, dt->r_no,
+ dt->r_ob, dt->r_obmat);
+}
+
+
/**
* Main Snapping Function
* ======================
@@ -1819,18 +2035,9 @@ static bool snapObject(
* 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: Mouse coords.
- * When NULL, ray-casting is handled without any projection matrix correction.
- * \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.
- * \param depth_range: distances of clipe plane min and clip plane max;
+ * \param snapdata: struct generated in `get_snapdata`.
+ * \param snap_select : from enum SnapSelect.
+ * \param use_object_edit_cage : Uses the coordinates of BMesh(if any) to do the snapping.
*
* Read/Write Args
* ---------------
@@ -1847,96 +2054,33 @@ static bool snapObject(
* (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],
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
- const float depth_range[2],
+ SnapObjectContext *sctx, SnapData *snapdata,
+ const SnapSelect snap_select, const bool use_object_edit_cage,
/* read/write args */
float *ray_depth, 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)
+ float r_loc[3], float r_no[3],
+ Object **r_ob, float r_obmat[4][4])
{
- bool retval = false;
-
- unsigned int ob_index = 0;
Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
- /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
- * which makes the loop skip it, even the derived mesh will never change
- *
- * To solve that problem, we do it first as an exception.
- * */
- Base *base_act = sctx->scene->basact;
- if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {
- Object *ob = base_act->object;
-
- retval |= snapObject(
- sctx, ob, ob->obmat, ob_index++,
- false, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
- ray_depth, dist_px,
- r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
- }
-
- bool ignore_object_selected = false, ignore_object_active = false;
- switch (snap_select) {
- case SNAP_ALL:
- break;
- case SNAP_NOT_SELECTED:
- ignore_object_selected = true;
- break;
- case SNAP_NOT_ACTIVE:
- ignore_object_active = true;
- break;
- }
- for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) {
- if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) &&
- (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
-
- !((ignore_object_selected && (base->flag & (SELECT | BA_WAS_SEL))) ||
- (ignore_object_active && base == base_act)))
- {
- Object *ob = base->object;
-
- if (ob->transflag & OB_DUPLI) {
- DupliObject *dupli_ob;
- ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, ob);
-
- for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data);
- Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
-
- retval |= snapObject(
- sctx, dupli_snap, dupli_ob->mat, ob_index++,
- use_obedit_dupli, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
- ray_depth, dist_px,
- r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
- }
-
- free_object_duplilist(lb);
- }
-
- bool use_obedit = (obedit != NULL) && (ob->data == obedit->data);
- Object *ob_snap = use_obedit ? obedit : ob;
+ struct SnapObjUserData data = {
+ .snapdata = snapdata,
+ .ray_depth = ray_depth,
+ .dist_px = dist_px,
+ .r_loc = r_loc,
+ .r_no = r_no,
+ .r_ob = r_ob,
+ .r_obmat = r_obmat,
+ .ret = false,
+ };
- retval |= snapObject(
- sctx, ob_snap, ob->obmat, ob_index++,
- use_obedit, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
- ray_depth, dist_px,
- r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
- }
- }
+ iter_snap_objects(sctx, snap_select, obedit, sanp_obj_cb, &data);
- return retval;
+ return data.ret;
}
/** \} */
@@ -1957,6 +2101,9 @@ SnapObjectContext *ED_transform_snap_object_context_create(
sctx->bmain = bmain;
sctx->scene = scene;
+ sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
+ sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
return sctx;
}
@@ -1971,11 +2118,6 @@ SnapObjectContext *ED_transform_snap_object_context_create_view3d(
sctx->v3d_data.ar = ar;
sctx->v3d_data.v3d = v3d;
- if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
- sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
- sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
-
return sctx;
}
@@ -1990,6 +2132,9 @@ static void snap_object_data_free(void *sod_v)
free_bvhtree_from_mesh(sod->bvh_trees[i]);
}
}
+ if (sod->poly_allocated) {
+ MEM_freeN(sod->mpoly);
+ }
break;
}
case SNAP_EDIT_MESH:
@@ -2007,10 +2152,8 @@ static void snap_object_data_free(void *sod_v)
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
{
- if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
- BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free);
- BLI_memarena_free(sctx->cache.mem_arena);
- }
+ BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free);
+ BLI_memarena_free(sctx->cache.mem_arena);
MEM_freeN(sctx);
}
@@ -2031,20 +2174,17 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
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,
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4])
{
- const float depth_range[2] = {0.0f, FLT_MAX};
- return snapObjectsRay(
+ return raycastObjects(
sctx,
- snap_to, params->snap_select, params->use_object_edit_cage, NULL,
- ray_start, ray_start, ray_normal, depth_range,
- ray_depth, NULL,
- r_loc, r_no, r_index, r_ob, r_obmat, NULL);
+ ray_start, ray_normal,
+ params->snap_select, params->use_object_edit_cage,
+ ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
/**
@@ -2056,13 +2196,11 @@ bool ED_transform_snap_object_project_ray_ex(
*/
bool ED_transform_snap_object_project_ray_all(
SnapObjectContext *sctx,
- const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float ray_depth, bool sort,
ListBase *r_hit_list)
{
- const float depth_range[2] = {0.0f, FLT_MAX};
if (ray_depth == -1.0f) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
@@ -2071,12 +2209,11 @@ bool ED_transform_snap_object_project_ray_all(
float ray_depth_prev = ray_depth;
#endif
- bool retval = snapObjectsRay(
+ bool retval = raycastObjects(
sctx,
- snap_to, params->snap_select, params->use_object_edit_cage, NULL,
- ray_start, ray_start, ray_normal, depth_range,
- &ray_depth, NULL,
- NULL, NULL, NULL, NULL, NULL,
+ ray_start, ray_normal,
+ params->snap_select, params->use_object_edit_cage,
+ &ray_depth, NULL, NULL, NULL, NULL, NULL,
r_hit_list);
/* meant to be readonly for 'all' hits, ensure it is */
@@ -2109,7 +2246,6 @@ static bool transform_snap_context_project_ray_impl(
/* try snap edge, then face if it fails */
ret = ED_transform_snap_object_project_ray_ex(
sctx,
- SCE_SNAP_MODE_FACE,
params,
ray_start, ray_normal, ray_depth,
r_co, r_no, NULL,
@@ -2153,19 +2289,40 @@ static bool transform_snap_context_project_view3d_mixed_impl(
BLI_assert(snap_to_flag != 0);
BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0);
- for (int i = 0; i < 3; i++) {
- if ((snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
- if (use_depth == false) {
- ray_depth = BVH_RAYCAST_DIST_MAX;
+ if (use_depth) {
+ const float dist_px_orig = dist_px ? *dist_px : 0;
+ for (int i = 2; i >= 0; i--) {
+ if (snap_to_flag & (1 << i)) {
+ if (i == 0) {
+ BLI_assert(dist_px != NULL);
+ *dist_px = dist_px_orig;
+ }
+ if (ED_transform_snap_object_project_view3d(
+ sctx,
+ elem_type[i], params,
+ mval, dist_px, &ray_depth,
+ r_co, r_no))
+ {
+ /* 0.01 is a random but small value to prioritizing
+ * the first elements of the loop */
+ ray_depth += 0.01f;
+ is_hit = true;
+ }
}
-
- if (ED_transform_snap_object_project_view3d(
- sctx,
- elem_type[i], params,
- mval, dist_px, &ray_depth,
- r_co, r_no))
- {
- is_hit = true;
+ }
+ }
+ else {
+ for (int i = 0; i < 3; i++) {
+ if (snap_to_flag & (1 << i)) {
+ if (ED_transform_snap_object_project_view3d(
+ sctx,
+ elem_type[i], params,
+ mval, dist_px, &ray_depth,
+ r_co, r_no))
+ {
+ is_hit = true;
+ break;
+ }
}
}
}
@@ -2234,12 +2391,24 @@ bool ED_transform_snap_object_project_view3d_ex(
ray_depth = &ray_depth_fallback;
}
- return snapObjectsRay(
- sctx,
- snap_to, params->snap_select, params->use_object_edit_cage,
- mval, ray_origin, ray_start, ray_normal, depth_range,
- ray_depth, dist_px,
- r_loc, r_no, r_index, NULL, NULL, NULL);
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ return raycastObjects(
+ sctx,
+ ray_start, ray_normal,
+ params->snap_select, params->use_object_edit_cage,
+ ray_depth, r_loc, r_no, r_index, NULL, NULL, NULL);
+ }
+ else {
+ SnapData snapdata;
+ const enum eViewProj view_proj = ((RegionView3D *)ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
+ snap_data_set(&snapdata, ar, snap_to, view_proj, mval,
+ ray_origin, ray_start, ray_normal, depth_range);
+
+ return snapObjectsRay(
+ sctx, &snapdata,
+ params->snap_select, params->use_object_edit_cage,
+ ray_depth, dist_px, r_loc, r_no, NULL, NULL);
+ }
}
bool ED_transform_snap_object_project_view3d(
@@ -2280,7 +2449,6 @@ bool ED_transform_snap_object_project_all_view3d_ex(
return ED_transform_snap_object_project_ray_all(
sctx,
- SCE_SNAP_MODE_FACE,
params,
ray_start, ray_normal, ray_depth, sort,
r_hit_list);
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index e07831358d6..61142fdc887 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -296,7 +296,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
}
/* Else, common behavior with DELKEY, only difference is remove char(s) before/after the cursor. */
dir = STRCUR_DIR_PREV;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case DELKEY:
if ((n->val_flag[idx] & NUM_EDITED) && n->str[0]) {
int t_cur = cur = n->str_cur;
@@ -322,7 +322,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
break;
case LEFTARROWKEY:
dir = STRCUR_DIR_PREV;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case RIGHTARROWKEY:
cur = n->str_cur;
if (event->ctrl) {
@@ -497,7 +497,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
n->unit_sys, n->unit_type[idx]);
/* Note: with angles, we always get values as radians here... */
- if (BPY_execute_string_as_number(C, str_unit_convert, &val, false)) {
+ if (BPY_execute_string_as_number(C, str_unit_convert, false, &val)) {
n->val[idx] = (float)val;
n->val_flag[idx] &= ~NUM_INVALID;
}
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index 4a9311416b3..419c15bf83f 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -327,6 +327,19 @@ static int ed_redo_exec(bContext *C, wmOperator *UNUSED(op))
return ed_undo_step(C, -1, NULL);
}
+static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ wmOperator *last_op = WM_operator_last_redo(C);
+ const int ret = ED_undo_operator_repeat(C, last_op);
+ return ret ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+static int ed_undo_redo_poll(bContext *C)
+{
+ wmOperator *last_op = WM_operator_last_redo(C);
+ return last_op && ED_operator_screenactive(C) &&
+ WM_operator_check_ui_enabled(C, last_op->type->name);
+}
/* ********************** */
@@ -369,6 +382,17 @@ void ED_OT_redo(wmOperatorType *ot)
ot->poll = ED_operator_screenactive;
}
+void ED_OT_undo_redo(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Undo and Redo";
+ ot->description = "Undo and redo previous action";
+ ot->idname = "ED_OT_undo_redo";
+
+ /* api callbacks */
+ ot->exec = ed_undo_redo_exec;
+ ot->poll = ed_undo_redo_poll;
+}
/* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
@@ -401,6 +425,9 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
if (G.debug & G_DEBUG)
printf("redo_cb: operator redo %s\n", op->type->name);
+
+ WM_operator_free_all_after(wm, op);
+
ED_undo_pop_op(C, op);
if (op->type->check) {
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 5c5e84ee5f0..15be6ab3b78 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -502,7 +502,7 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
ma = give_current_material(ob, ob->actcol);
- if (me->mtpoly) {
+ if (me->mloopuv) {
MPoly *mpoly = me->mpoly;
MLoopUV *mloopuv, *mloopuv_base;
int a, b;
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 193b006cf0d..75294af08f9 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -225,7 +225,7 @@ void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, I
BM_data_layer_add(em->bm, &em->bm->pdata, CD_MTEXPOLY);
BM_data_layer_add(em->bm, &em->bm->ldata, CD_MLOOPUV);
/* make UVs all nice 0-1 */
- ED_mesh_uv_loop_reset_ex(obedit->data, CustomData_get_active_layer_index(&em->bm->pdata, CD_MTEXPOLY));
+ ED_mesh_uv_loop_reset_ex(obedit->data, CustomData_get_active_layer(&em->bm->pdata, CD_MTEXPOLY));
update = true;
}
@@ -1136,8 +1136,13 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
- /* use winding so we don't consider overlapping islands as connected, see T44320 */
- vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, true);
+ /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
+ * this made *every* projection split the island into front/back islands.
+ * Keep 'use_winding' to false, see: T50970.
+ *
+ * Better solve this by having a delimit option for select-linked operator,
+ * keeping island-select working as is. */
+ vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
if (vmap == NULL)
return;
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index bdfff123aa4..8c76d03035a 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -2859,7 +2859,7 @@ static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PV
PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe;
float maxlen = 0.0f, curlen = 0.0f, totlen = 0.0f, firstlen = 0.0f;
float len1, len2;
-
+
/* find longest series of verts split in the chart itself, these are
* marked during construction */
be = outer;
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 59442e89787..d5233f0ed28 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -459,7 +459,7 @@ static void stitch_calculate_island_snapping(
island_stitch_data[i].num_rot_elements_neg) / totelem;
}
- rotate_m2(rotation_mat, rotation);
+ angle_to_mat2(rotation_mat, rotation);
numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
element = &state->element_map->buf[state->element_map->islandIndices[i]];
for (j = 0; j < numOfIslandUVs; j++, element++) {
@@ -2116,6 +2116,7 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
break;
}
+ ATTR_FALLTHROUGH;
case PADENTER:
case RETKEY:
if (event->val == KM_PRESS) {
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 8e4ba4c0afa..d8080002818 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -1222,7 +1222,7 @@ static int unwrap_exec(bContext *C, wmOperator *op)
* pass operator for warning append */
modifier_unwrap_state(obedit, scene, &use_subsurf_final);
if (use_subsurf != use_subsurf_final)
- BKE_report(op->reports, RPT_INFO, "Subsurf modifier needs to be first to work with unwrap");
+ BKE_report(op->reports, RPT_INFO, "Subdivision Surface modifier needs to be first to work with unwrap");
/* execute unwrap */
ED_unwrap_lscm(scene, obedit, true);
@@ -1259,7 +1259,7 @@ void UV_OT_unwrap(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect",
"Map UVs taking image aspect ratio into account");
RNA_def_boolean(ot->srna, "use_subsurf_data", 0, "Use Subsurf Modifier",
- "Map UVs taking vertex position after subsurf into account");
+ "Map UVs taking vertex position after Subdivision Surface modifier has been applied");
RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
}
diff --git a/source/blender/freestyle/intern/application/AppView.cpp b/source/blender/freestyle/intern/application/AppView.cpp
index c331d1de9c9..9b1b02c8ee2 100644
--- a/source/blender/freestyle/intern/application/AppView.cpp
+++ b/source/blender/freestyle/intern/application/AppView.cpp
@@ -22,12 +22,6 @@
* \ingroup freestyle
*/
-/* This header file needs to be included first, in order to avoid a
- compilation with MinGW (see the commit log of revision 28253) */
-extern "C" {
-#include "BLI_jitter.h"
-}
-
#include <iostream>
#include "Controller.h"
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index f63cf771120..9c478c203e7 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -524,7 +524,7 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
// We'll generate both with tips and without tips
// coordinates, on two different UV layers.
- if (ma->mtex[a]->texflag & MTEX_TIPS) {
+ if (ma->mtex[a]->texflag & MTEX_TIPS) {
BLI_strncpy(ma->mtex[a]->uvname, uvNames[1], sizeof(ma->mtex[a]->uvname));
}
else {
@@ -957,7 +957,7 @@ Render *BlenderStrokeRenderer::RenderScene(Render * /*re*/, bool render)
}
#endif
- Render *freestyle_render = RE_NewRender(freestyle_scene->id.name);
+ Render *freestyle_render = RE_NewSceneRender(freestyle_scene);
RE_RenderFreestyleStrokes(freestyle_render, freestyle_bmain, freestyle_scene,
render && get_stroke_count() > 0);
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index 2af4447e4dc..ea22633c50e 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -433,8 +433,8 @@ static void prepare(Render *re, SceneRenderLayer *srl)
cout << "Crease angle : " << controller->getCreaseAngle() << endl;
cout << "Sphere radius : " << controller->getSphereRadius() << endl;
cout << "Face smoothness : " << (controller->getFaceSmoothness() ? "enabled" : "disabled") << endl;
- cout << "Redges and valleys : " << (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled") <<
- endl;
+ cout << "Ridges and valleys : " <<
+ (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled") << endl;
cout << "Suggestive contours : " <<
(controller->getComputeSuggestiveContoursFlag() ? "enabled" : "disabled") << endl;
cout << "Suggestive contour Kr derivative epsilon : " <<
@@ -448,15 +448,13 @@ static void prepare(Render *re, SceneRenderLayer *srl)
RenderLayer *rl = RE_GetRenderLayer(re->result, srl->name);
bool diffuse = false, z = false;
for (RenderPass *rpass = (RenderPass *)rl->passes.first; rpass; rpass = rpass->next) {
- switch (rpass->passtype) {
- case SCE_PASS_DIFFUSE:
+ if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
controller->setPassDiffuse(rpass->rect, rpass->rectx, rpass->recty);
diffuse = true;
- break;
- case SCE_PASS_Z:
+ }
+ if (STREQ(rpass->name, RE_PASSNAME_Z)) {
controller->setPassZ(rpass->rect, rpass->rectx, rpass->recty);
z = true;
- break;
}
}
if (G.debug & G_DEBUG_FREESTYLE) {
@@ -492,7 +490,7 @@ void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_r
return;
}
- src = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, freestyle_render->viewname);
+ src = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, freestyle_render->viewname);
if (!src) {
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "No source result image to composite" << endl;
@@ -512,7 +510,7 @@ void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_r
}
return;
}
- dest = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname);
+ dest = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, re->viewname);
if (!dest) {
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "No destination result image to composite to" << endl;
diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.cpp b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
index 3eb92c559fe..cd7c1b83a4e 100644
--- a/source/blender/freestyle/intern/geometry/GeomUtils.cpp
+++ b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
@@ -470,6 +470,8 @@ bool intersectRayTriangle(const Vec3r& orig, const Vec3r& dir, const Vec3r& v0,
}
// Intersection between plane and ray, adapted from Graphics Gems, Didier Badouel
+// The plane is represented by a set of points P implicitly defined as dot(norm, P) + d = 0.
+// The ray is represented as r(t) = orig + dir * t.
intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, const Vec3r& norm, const real d,
real& t, const real epsilon)
{
diff --git a/source/blender/freestyle/intern/geometry/matrix_util.h b/source/blender/freestyle/intern/geometry/matrix_util.h
index d65b0ea803b..444fd7c4785 100644
--- a/source/blender/freestyle/intern/geometry/matrix_util.h
+++ b/source/blender/freestyle/intern/geometry/matrix_util.h
@@ -50,15 +50,15 @@ namespace MatrixUtil {
/**
* computes the eigen values and eigen vectors of a semi definite symmetric matrix
*
- * @param matrix is stored in column symmetric storage, i.e.
+ * \param mat: The matrix stored in column symmetric storage, i.e.
* matrix = { m11, m12, m22, m13, m23, m33, m14, m24, m34, m44 ... }
* size = n(n+1)/2
*
- * @param eigen_vectors (return) = { v1, v2, v3, ..., vn }
+ * \param eigen_vec: (return) = { v1, v2, v3, ..., vn }
* where vk = vk0, vk1, ..., vkn
* size = n^2, must be allocated by caller
*
- * @param eigen_values (return) are in decreasing order
+ * \param eigen_val: (return) are in decreasing order
* size = n, must be allocated by caller
*/
void semi_definite_symmetric_eigen(const double *mat, int n, double *eigen_vec, double *eigen_val);
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
index 380bb0dd3ca..794c782bb73 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
@@ -57,7 +57,7 @@ using namespace std;
template <typename G, typename I>
static void findOccludee(FEdge *fe, G& /*grid*/, I& occluders, real epsilon, WFace **oaWFace,
- Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices)
+ Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector<WVertex*>& faceVertices)
{
WFace *face = NULL;
if (fe->isSmooth()) {
@@ -125,7 +125,7 @@ static void findOccludee(FEdge *fe, G& /*grid*/, I& occluders, real epsilon, WFa
// check whether the edge and the polygon plane are coincident:
//-------------------------------------------------------------
//first let us compute the plane equation.
- if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, p->getNormal(), d, t, epsilon))
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, p->getNormal(), d, t, epsilon))
{
#if LOGGING
if (_global.debug & G_DEBUG_FREESTYLE) {
@@ -172,10 +172,11 @@ template <typename G, typename I>
static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WFace **oaFace)
{
Vec3r A;
- Vec3r edge;
+ Vec3r edgeDir;
Vec3r origin;
A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0);
- edge = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
+ edgeDir = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
+ edgeDir.normalize();
origin = Vec3r((fe)->vertexA()->point3D());
Vec3r u;
if (grid.orthographicProjection()) {
@@ -199,7 +200,7 @@ static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WF
}
I occluders(grid, A, epsilon);
- findOccludee<G, I>(fe, grid, occluders, epsilon, oaFace, u, A, origin, edge, faceVertices);
+ findOccludee<G, I>(fe, grid, occluders, epsilon, oaFace, u, A, origin, edgeDir, faceVertices);
}
// computeVisibility takes a pointer to foundOccluders, instead of using a reference,
@@ -211,11 +212,12 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon,
int qi = 0;
Vec3r center;
- Vec3r edge;
+ Vec3r edgeDir;
Vec3r origin;
center = fe->center3d();
- edge = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
+ edgeDir = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
+ edgeDir.normalize();
origin = Vec3r(fe->vertexA()->point3D());
Vec3r vp;
@@ -337,7 +339,7 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon,
// check whether the edge and the polygon plane are coincident:
//-------------------------------------------------------------
//first let us compute the plane equation.
- if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, p->getNormal(), d, t, epsilon)) {
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, p->getNormal(), d, t, epsilon)) {
#if LOGGING
if (_global.debug & G_DEBUG_FREESTYLE) {
cout << "\t\tRejecting occluder for target coincidence." << endl;
@@ -391,7 +393,7 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon,
}
// Find occludee
- findOccludee<G, I>(fe, grid, occluders, epsilon, oaWFace, u, center, origin, edge, faceVertices);
+ findOccludee<G, I>(fe, grid, occluders, epsilon, oaWFace, u, center, origin, edgeDir, faceVertices);
return qi;
}
@@ -1788,7 +1790,7 @@ void ViewMapBuilder::ComputeVeryFastRayCastingVisibility(ViewMap *ioViewMap, rea
}
void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp,
- Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices)
+ Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector<WVertex*>& faceVertices)
{
WFace *face = NULL;
if (fe->isSmooth()) {
@@ -1856,7 +1858,7 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3
continue;
}
else {
- if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon))
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, normal, d, t, epsilon))
continue;
}
if ((*p)->rayIntersect(A, v, t, t_u, t_v)) {
@@ -1883,10 +1885,11 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3
OccludersSet occluders;
Vec3r A;
- Vec3r edge;
+ Vec3r edgeDir;
Vec3r origin;
A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0);
- edge = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
+ edgeDir = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
+ edgeDir.normalize();
origin = Vec3r((fe)->vertexA()->point3D());
Vec3r u;
if (_orthographicProjection) {
@@ -1910,7 +1913,7 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3
if (face)
face->RetrieveVertexList(faceVertices);
- return FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, A, origin, edge, faceVertices);
+ return FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, A, origin, edgeDir, faceVertices);
}
int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real epsilon, set<ViewShape*>& oOccluders,
@@ -1920,11 +1923,12 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps
int qi = 0;
Vec3r center;
- Vec3r edge;
+ Vec3r edgeDir;
Vec3r origin;
center = fe->center3d();
- edge = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
+ edgeDir = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
+ edgeDir.normalize();
origin = Vec3r(fe->vertexA()->point3D());
// Is the edge outside the view frustum ?
Vec3r gridOrigin(iGrid->getOrigin());
@@ -2062,7 +2066,7 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps
//-------------------------------------------------------------
//first let us compute the plane equation.
- if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon)) {
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, normal, d, t, epsilon)) {
#if LOGGING
if (_global.debug & G_DEBUG_FREESTYLE) {
cout << "\t\tRejecting occluder for target coincidence." << endl;
@@ -2099,7 +2103,7 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps
}
// Find occludee
- FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, origin, edge, faceVertices);
+ FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, origin, edgeDir, faceVertices);
return qi;
}
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
index 36497bf8d22..440ae93c7df 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
@@ -250,7 +250,7 @@ protected:
// FIXME
void FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp);
void FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp,
- Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices);
+ Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector<WVertex*>& faceVertices);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:ViewMapBuilder")
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 8885209ce01..885ff2ff159 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -57,6 +57,8 @@ set(SRC
intern/gpu_init_exit.c
intern/gpu_material.c
intern/gpu_select.c
+ intern/gpu_select_pick.c
+ intern/gpu_select_sample_query.c
intern/gpu_shader.c
intern/gpu_texture.c
@@ -97,6 +99,7 @@ set(SRC
GPU_texture.h
intern/gpu_codegen.h
intern/gpu_private.h
+ intern/gpu_select_private.h
)
data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index b693d473bd8..e4a837d0a5f 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -222,50 +222,53 @@ void GPU_interleaved_attrib_unbind(void);
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
/* build */
-GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
+GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(
const int (*face_vert_indices)[3],
const struct MPoly *mpoly, const struct MLoop *mloop, const struct MLoopTri *looptri,
const struct MVert *verts,
const int *face_indices,
const int face_indices_len);
-GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
+GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(
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);
+GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
/* update */
-void GPU_update_mesh_pbvh_buffers(
+void GPU_pbvh_mesh_buffers_update(
GPU_PBVH_Buffers *buffers, const struct MVert *mvert,
const int *vert_indices, int totvert, const float *vmask,
const int (*face_vert_indices)[3], bool show_diffuse_color);
-void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
- struct BMesh *bm,
- struct GSet *bm_faces,
- struct GSet *bm_unique_verts,
- struct GSet *bm_other_verts,
- bool show_diffuse_color);
+void GPU_pbvh_bmesh_buffers_update(
+ GPU_PBVH_Buffers *buffers,
+ struct BMesh *bm,
+ struct GSet *bm_faces,
+ struct GSet *bm_unique_verts,
+ struct GSet *bm_other_verts,
+ bool show_diffuse_color);
-void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, struct CCGElem **grids,
- const struct DMFlagMat *grid_flag_mats,
- int *grid_indices, int totgrid, const struct CCGKey *key,
- bool show_diffuse_color);
+void GPU_pbvh_grid_buffers_update(
+ GPU_PBVH_Buffers *buffers, struct CCGElem **grids,
+ const struct DMFlagMat *grid_flag_mats,
+ int *grid_indices, int totgrid, const struct CCGKey *key,
+ bool show_diffuse_color);
/* draw */
-void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
- bool wireframe, bool fast);
+void GPU_pbvh_buffers_draw(
+ GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
+ bool wireframe, bool fast);
/* debug PBVH draw*/
-void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf);
-void GPU_end_draw_pbvh_BB(void);
-void GPU_init_draw_pbvh_BB(void);
+void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf);
+void GPU_pbvh_BB_draw_init(void);
+void GPU_pbvh_BB_draw_end(void);
bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, struct GSet *bm_faces, bool show_diffuse_color);
-void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers);
-void GPU_free_pbvh_buffer_multires(struct GridCommonGPUBuffer **grid_common_gpu_buffer);
+void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
+void GPU_pbvh_multires_buffers_free(struct GridCommonGPUBuffer **grid_common_gpu_buffer);
#endif
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 0d92d22a173..dbfcd4d1ea4 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -98,6 +98,7 @@ typedef enum GPUBuiltin {
GPU_PARTICLE_ANG_VELOCITY = (1 << 12),
GPU_LOC_TO_VIEW_MATRIX = (1 << 13),
GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14),
+ GPU_OBJECT_INFO = (1 << 15)
} GPUBuiltin;
typedef enum GPUOpenGLBuiltin {
@@ -213,6 +214,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
void GPU_material_enable_alpha(GPUMaterial *material);
+GPUBuiltin GPU_get_material_builtins(GPUMaterial *material);
GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]);
/* High level functions to create and use GPU materials */
@@ -224,13 +226,13 @@ void GPU_material_free(struct ListBase *gpumaterial);
void GPU_materials_free(void);
-bool GPU_lamp_override_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma);
+bool GPU_lamp_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma);
void GPU_material_bind(
GPUMaterial *material, int oblay, int viewlay, double time, int mipmap,
float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock);
void GPU_material_bind_uniforms(
GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
- float autobumpscale, GPUParticleInfo *pi);
+ float autobumpscale, GPUParticleInfo *pi, float object_info[3]);
void GPU_material_unbind(GPUMaterial *material);
bool GPU_material_bound(GPUMaterial *material);
struct Scene *GPU_material_scene(GPUMaterial *material);
@@ -345,6 +347,7 @@ struct GPUParticleInfo
float location[3];
float velocity[3];
float angular_velocity[3];
+ int random_id;
};
#ifdef WITH_OPENSUBDIV
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
index 6a16b5b7456..cf5b8bf7d8f 100644
--- a/source/blender/gpu/GPU_select.h
+++ b/source/blender/gpu/GPU_select.h
@@ -30,19 +30,30 @@
#ifndef __GPU_SELECT_H__
#define __GPU_SELECT_H__
-#include "DNA_vec_types.h" /* rcft */
#include "BLI_sys_types.h"
+struct rcti;
+
/* flags for mode of operation */
enum {
GPU_SELECT_ALL = 1,
+ /* gpu_select_query */
GPU_SELECT_NEAREST_FIRST_PASS = 2,
GPU_SELECT_NEAREST_SECOND_PASS = 3,
+ /* gpu_select_pick */
+ GPU_SELECT_PICK_ALL = 4,
+ GPU_SELECT_PICK_NEAREST = 5,
};
-void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits);
+void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const struct rcti *input, char mode, int oldhits);
bool GPU_select_load_id(unsigned int id);
unsigned int GPU_select_end(void);
bool GPU_select_query_check_active(void);
+/* cache selection region */
+bool GPU_select_is_cached(void);
+void GPU_select_cache_begin(void);
+void GPU_select_cache_load_id(void);
+void GPU_select_cache_end(void);
+
#endif
diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c
index a2b89239344..8505bd847a0 100644
--- a/source/blender/gpu/intern/gpu_basic_shader.c
+++ b/source/blender/gpu/intern/gpu_basic_shader.c
@@ -407,7 +407,7 @@ static GPUShader *gpu_basic_shader(int options)
return shader;
}
-static void GPU_basic_shader_uniform_autoset(GPUShader *shader, int options)
+static void gpu_basic_shader_uniform_autoset(GPUShader *shader, int options)
{
if (options & GPU_SHADER_LINE) {
glGetIntegerv(GL_VIEWPORT, &GPU_MATERIAL_STATE.viewport[0]);
@@ -443,7 +443,7 @@ void GPU_basic_shader_bind(int options)
if (shader) {
GPU_shader_bind(shader);
- GPU_basic_shader_uniform_autoset(shader, options);
+ gpu_basic_shader_uniform_autoset(shader, options);
}
}
else {
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 370841327aa..e288c74fee6 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -76,13 +76,13 @@ typedef struct {
static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type);
-const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
+static const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
/* vertex */
{GL_ARRAY_BUFFER, 3},
/* normal */
{GL_ARRAY_BUFFER, 4}, /* we copy 3 shorts per normal but we add a fourth for alignment */
/* mcol */
- {GL_ARRAY_BUFFER, 3},
+ {GL_ARRAY_BUFFER, 4},
/* uv */
{GL_ARRAY_BUFFER, 2},
/* uv for texpaint */
@@ -690,7 +690,7 @@ void GPU_color_setup(DerivedMesh *dm, int colType)
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->colors->id);
- glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
+ glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);
GLStates |= GPU_BUFFER_COLOR_STATE;
}
@@ -743,7 +743,7 @@ void GPU_triangle_setup(struct DerivedMesh *dm)
GLStates |= GPU_BUFFER_ELEMENT_STATE;
}
-static int GPU_typesize(int type)
+static int gpu_typesize(int type)
{
switch (type) {
case GL_FLOAT:
@@ -766,7 +766,7 @@ int GPU_attrib_element_size(GPUAttrib data[], int numdata)
int i, elementsize = 0;
for (i = 0; i < numdata; i++) {
- int typesize = GPU_typesize(data[i].type);
+ int typesize = gpu_typesize(data[i].type);
if (typesize != 0)
elementsize += typesize * data[i].size;
}
@@ -803,7 +803,7 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
glVertexAttribPointer(data[i].index, data[i].size, data[i].type,
GL_TRUE, elementsize, BUFFER_OFFSET(offset));
- offset += data[i].size * GPU_typesize(data[i].type);
+ offset += data[i].size * gpu_typesize(data[i].type);
attribData[i].index = data[i].index;
attribData[i].size = data[i].size;
@@ -1030,13 +1030,13 @@ static void gpu_color_from_mask_quad_copy(const CCGKey *key,
out[2] = diffuse_color[2] * mask_color;
}
-void GPU_update_mesh_pbvh_buffers(
+void GPU_pbvh_mesh_buffers_update(
GPU_PBVH_Buffers *buffers, const MVert *mvert,
const int *vert_indices, int totvert, const float *vmask,
const int (*face_vert_indices)[3], bool show_diffuse_color)
{
VertexBufferFormat *vert_data;
- int i, j;
+ int i;
buffers->vmask = vmask;
buffers->show_diffuse_color = show_diffuse_color;
@@ -1057,6 +1057,9 @@ void GPU_update_mesh_pbvh_buffers(
copy_v4_v4(buffers->diffuse_color, diffuse_color);
+ uchar diffuse_color_ub[4];
+ rgba_float_to_uchar(diffuse_color_ub, diffuse_color);
+
/* Build VBO */
if (buffers->vert_buf)
GPU_buffer_free(buffers->vert_buf);
@@ -1076,28 +1079,20 @@ void GPU_update_mesh_pbvh_buffers(
memcpy(out->no, v->no, sizeof(short) * 3);
}
-#define UPDATE_VERTEX(face, vertex, index, diffuse_color) \
- { \
- VertexBufferFormat *out = vert_data + face_vert_indices[face][index]; \
- if (vmask) \
- gpu_color_from_mask_copy(vmask[vertex], diffuse_color, out->color); \
- else \
- rgb_float_to_uchar(out->color, diffuse_color); \
- } (void)0
-
for (i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
- const unsigned int vtri[3] = {
- buffers->mloop[lt->tri[0]].v,
- buffers->mloop[lt->tri[1]].v,
- buffers->mloop[lt->tri[2]].v,
- };
+ for (uint j = 0; j < 3; j++) {
+ VertexBufferFormat *out = vert_data + face_vert_indices[i][j];
- UPDATE_VERTEX(i, vtri[0], 0, diffuse_color);
- UPDATE_VERTEX(i, vtri[1], 1, diffuse_color);
- UPDATE_VERTEX(i, vtri[2], 2, diffuse_color);
+ if (vmask) {
+ uint v_index = buffers->mloop[lt->tri[j]].v;
+ gpu_color_from_mask_copy(vmask[v_index], diffuse_color, out->color);
+ }
+ else {
+ copy_v3_v3_uchar(out->color, diffuse_color_ub);
+ }
+ }
}
-#undef UPDATE_VERTEX
}
else {
/* calculate normal for each polygon only once */
@@ -1112,8 +1107,6 @@ void GPU_update_mesh_pbvh_buffers(
buffers->mloop[lt->tri[2]].v,
};
- float fmask;
-
if (paint_is_face_hidden(lt, mvert, buffers->mloop))
continue;
@@ -1126,23 +1119,22 @@ void GPU_update_mesh_pbvh_buffers(
mpoly_prev = lt->poly;
}
+ uchar color_ub[3];
if (vmask) {
- fmask = (vmask[vtri[0]] +
- vmask[vtri[1]] +
- vmask[vtri[2]]) / 3.0f;
+ float fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f;
+ gpu_color_from_mask_copy(fmask, diffuse_color, color_ub);
+ }
+ else {
+ copy_v3_v3_uchar(color_ub, diffuse_color_ub);
}
- for (j = 0; j < 3; j++) {
+ for (uint j = 0; j < 3; j++) {
const MVert *v = &mvert[vtri[j]];
VertexBufferFormat *out = vert_data;
copy_v3_v3(out->co, v->co);
copy_v3_v3_short(out->no, no);
-
- if (vmask)
- gpu_color_from_mask_copy(fmask, diffuse_color, out->color);
- else
- rgb_float_to_uchar(out->color, diffuse_color);
+ copy_v3_v3_uchar(out->color, color_ub);
vert_data++;
}
@@ -1160,7 +1152,7 @@ void GPU_update_mesh_pbvh_buffers(
buffers->mvert = mvert;
}
-GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
+GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(
const int (*face_vert_indices)[3],
const MPoly *mpoly, const MLoop *mloop, const MLoopTri *looptri,
const MVert *mvert,
@@ -1244,9 +1236,10 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
return buffers;
}
-void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
- const DMFlagMat *grid_flag_mats, int *grid_indices,
- int totgrid, const CCGKey *key, bool show_diffuse_color)
+void GPU_pbvh_grid_buffers_update(
+ GPU_PBVH_Buffers *buffers, CCGElem **grids,
+ const DMFlagMat *grid_flag_mats, int *grid_indices,
+ int totgrid, const CCGKey *key, bool show_diffuse_color)
{
VertexBufferFormat *vert_data;
int i, j, k, x, y;
@@ -1466,7 +1459,7 @@ static GPUBuffer *gpu_get_grid_buffer(
} \
} (void)0
-GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
+GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(
int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key,
GridCommonGPUBuffer **grid_common_gpu_buffer)
{
@@ -1612,12 +1605,13 @@ static int gpu_bmesh_face_visible_count(GSet *bm_faces)
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
* shading, an element index buffer. */
-void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
- BMesh *bm,
- GSet *bm_faces,
- GSet *bm_unique_verts,
- GSet *bm_other_verts,
- bool show_diffuse_color)
+void GPU_pbvh_bmesh_buffers_update(
+ GPU_PBVH_Buffers *buffers,
+ BMesh *bm,
+ GSet *bm_faces,
+ GSet *bm_unique_verts,
+ GSet *bm_other_verts,
+ bool show_diffuse_color)
{
VertexBufferFormat *vert_data;
void *tri_data;
@@ -1803,7 +1797,7 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
}
}
-GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading)
+GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
{
GPU_PBVH_Buffers *buffers;
@@ -1816,8 +1810,9 @@ GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading)
return buffers;
}
-void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
- bool wireframe, bool fast)
+void GPU_pbvh_buffers_draw(
+ GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
+ bool wireframe, bool fast)
{
bool do_fast = fast && buffers->index_buf_fast;
/* sets material from the first face, to solve properly face would need to
@@ -1956,7 +1951,8 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
}
}
-bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color)
+bool GPU_pbvh_buffers_diffuse_changed(
+ GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color)
{
float diffuse_color[4];
bool use_matcaps = GPU_material_use_matcaps_get();
@@ -1999,7 +1995,7 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces,
return !equals_v3v3(diffuse_color, buffers->diffuse_color);
}
-void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
+void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
{
if (buffers) {
if (buffers->vert_buf)
@@ -2017,7 +2013,7 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
}
}
-void GPU_free_pbvh_buffer_multires(GridCommonGPUBuffer **grid_common_gpu_buffer)
+void GPU_pbvh_multires_buffers_free(GridCommonGPUBuffer **grid_common_gpu_buffer)
{
GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer;
@@ -2033,7 +2029,7 @@ void GPU_free_pbvh_buffer_multires(GridCommonGPUBuffer **grid_common_gpu_buffer)
}
/* debug function, draws the pbvh BB */
-void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf)
+void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf)
{
const float quads[4][4][3] = {
{
@@ -2074,7 +2070,7 @@ void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf)
glDrawArrays(GL_QUADS, 0, 16);
}
-void GPU_init_draw_pbvh_BB(void)
+void GPU_pbvh_BB_draw_init(void)
{
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_CULL_FACE);
@@ -2084,7 +2080,7 @@ void GPU_init_draw_pbvh_BB(void)
glEnable(GL_BLEND);
}
-void GPU_end_draw_pbvh_BB(void)
+void GPU_pbvh_BB_draw_end(void)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glPopAttrib();
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 211394e7932..b5512aa108d 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -360,7 +360,7 @@ static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data)
BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]);
for (i = 0; i < type; i++) {
- BLI_dynstr_appendf(ds, "%f", data[i]);
+ BLI_dynstr_appendf(ds, "%.12f", data[i]);
if (i == type - 1)
BLI_dynstr_append(ds, ")");
else
@@ -410,6 +410,8 @@ const char *GPU_builtin_name(GPUBuiltin builtin)
return "unfparticlevel";
else if (builtin == GPU_PARTICLE_ANG_VELOCITY)
return "unfparticleangvel";
+ else if (builtin == GPU_OBJECT_INFO)
+ return "unfobjectinfo";
else
return "";
}
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
index 964c2b5051e..2f2a16f9e1d 100644
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -798,7 +798,9 @@ bool GPU_fx_do_composite_pass(
ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp);
if (ssao_shader) {
const GPUSSAOSettings *fx_ssao = fx->settings.ssao;
- float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f};
+ /* adjust attenuation to be scale invariant */
+ float attenuation = fx_ssao->attenuation / (fx_ssao->distance_max * fx_ssao->distance_max);
+ float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, attenuation, 0.0f};
float sample_params[3];
sample_params[0] = fx->ssao_sample_count_cache;
diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c
index d632e767ca9..7a0562617d6 100644
--- a/source/blender/gpu/intern/gpu_debug.c
+++ b/source/blender/gpu/intern/gpu_debug.c
@@ -29,6 +29,7 @@
* \ingroup gpu
*/
+#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
#include "BLI_sys_types.h"
#include "BLI_system.h"
@@ -161,7 +162,7 @@ const char *gpuErrorString(GLenum err)
#endif
-static const char* source_name(GLenum source)
+static const char *source_name(GLenum source)
{
switch (source) {
case GL_DEBUG_SOURCE_API: return "API";
@@ -174,7 +175,7 @@ static const char* source_name(GLenum source)
}
}
-static const char* message_type_name(GLenum message)
+static const char *message_type_name(GLenum message)
{
switch (message) {
case GL_DEBUG_TYPE_ERROR: return "error";
@@ -188,7 +189,7 @@ static const char* message_type_name(GLenum message)
}
}
-static const char* category_name_amd(GLenum category)
+static const char *category_name_amd(GLenum category)
{
switch (category) {
case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error";
@@ -219,7 +220,7 @@ static void APIENTRY gpu_debug_proc(
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH:
backtrace = true;
- /* fall through */
+ ATTR_FALLTHROUGH;
case GL_DEBUG_SEVERITY_MEDIUM:
case GL_DEBUG_SEVERITY_LOW:
case GL_DEBUG_SEVERITY_NOTIFICATION: /* KHR has this, ARB does not */
@@ -249,7 +250,7 @@ static void APIENTRY gpu_debug_proc_amd(
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH:
backtrace = true;
- /* fall through */
+ ATTR_FALLTHROUGH;
case GL_DEBUG_SEVERITY_MEDIUM:
case GL_DEBUG_SEVERITY_LOW:
fprintf(stderr, "GL %s: %s\n", category_name_amd(category), message);
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 7936811ab4d..2d7fa760e49 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -45,6 +45,7 @@
#include "BLI_math.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_hash.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
@@ -681,10 +682,10 @@ int GPU_verify_image(
if (do_color_management) {
srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "floar_buf_col_cor");
gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf);
- frect = srgb_frect + texwinsy * ibuf->x + texwinsx;
+ frect = srgb_frect + (4 * (texwinsy * ibuf->x + texwinsx));
}
else {
- frect = ibuf->rect_float + texwinsy * ibuf->x + texwinsx;
+ frect = ibuf->rect_float + (ibuf->channels * (texwinsy * ibuf->x + texwinsx));
}
}
else {
@@ -1203,7 +1204,7 @@ void GPU_paint_set_mipmap(bool mipmap)
/* check if image has been downscaled and do scaled partial update */
-static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
+static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
{
if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) ||
is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y))
@@ -1296,7 +1297,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0;
IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data);
- if (GPU_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
+ if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
MEM_freeN(buffer);
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
@@ -1320,7 +1321,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
return;
}
- if (GPU_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) {
+ if (gpu_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) {
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
}
@@ -1870,7 +1871,7 @@ void GPU_begin_object_materials(
GPU_object_material_unbind();
}
-static int GPU_get_particle_info(GPUParticleInfo *pi)
+static int gpu_get_particle_info(GPUParticleInfo *pi)
{
DupliObject *dob = GMS.dob;
if (dob->particle_system) {
@@ -1899,6 +1900,21 @@ static int GPU_get_particle_info(GPUParticleInfo *pi)
return 0;
}
+static void GPU_get_object_info(float oi[3], Material *mat)
+{
+ Object *ob = GMS.gob;
+ oi[0] = ob->index;
+ oi[1] = mat->index;
+ unsigned int random;
+ if (GMS.dob) {
+ random = GMS.dob->random_id;
+ }
+ else {
+ random = BLI_hash_int_2d(BLI_hash_string(GMS.gob->id.name + 2), 0);
+ }
+ oi[2] = random * (1.0f / (float)0xFFFFFFFF);
+}
+
int GPU_object_material_bind(int nr, void *attribs)
{
GPUVertexAttribs *gattribs = attribs;
@@ -1958,21 +1974,27 @@ int GPU_object_material_bind(int nr, void *attribs)
/* bind glsl material and get attributes */
Material *mat = GMS.gmatbuf[nr];
GPUParticleInfo partile_info;
+ float object_info[3] = {0};
float auto_bump_scale;
GPUMaterial *gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv);
GPU_material_vertex_attributes(gpumat, gattribs);
- if (GMS.dob)
- GPU_get_particle_info(&partile_info);
+ if (GMS.dob) {
+ gpu_get_particle_info(&partile_info);
+ }
+
+ if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) {
+ GPU_get_object_info(object_info, mat);
+ }
GPU_material_bind(
gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT),
GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock);
auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
- GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info);
+ GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info);
GMS.gboundmat = mat;
/* for glsl use alpha blend mode, unless it's set to solid and
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index f62ef677434..e7a8beae5cc 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -52,7 +52,7 @@ struct GPUFrameBuffer {
GPUTexture *depthtex;
};
-static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
+static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
{
const char *err = "unknown";
@@ -164,7 +164,7 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot
if (error == GL_INVALID_OPERATION) {
GPU_framebuffer_restore();
- GPU_print_framebuffer_error(error, err_out);
+ gpu_print_framebuffer_error(error, err_out);
return 0;
}
@@ -331,7 +331,7 @@ bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
GPU_framebuffer_restore();
- GPU_print_framebuffer_error(status, err_out);
+ gpu_print_framebuffer_error(status, err_out);
return false;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index b857aea29ad..f39cad20b9b 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -122,6 +122,8 @@ struct GPUMaterial {
int partvel;
int partangvel;
+ int objectinfoloc;
+
ListBase lamps;
bool bound;
@@ -225,7 +227,7 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
attribs->totlayer = b;
}
-static int GPU_material_construct_end(GPUMaterial *material, const char *passname)
+static int gpu_material_construct_end(GPUMaterial *material, const char *passname)
{
if (material->outlink) {
GPUNodeLink *outlink = material->outlink;
@@ -268,6 +270,8 @@ static int GPU_material_construct_end(GPUMaterial *material, const char *passnam
material->partvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_VELOCITY));
if (material->builtins & GPU_PARTICLE_ANG_VELOCITY)
material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY));
+ if (material->builtins & GPU_OBJECT_INFO)
+ material->objectinfoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_INFO));
return 1;
}
else {
@@ -308,9 +312,11 @@ void GPU_material_free(ListBase *gpumaterial)
BLI_freelistN(gpumaterial);
}
-bool GPU_lamp_override_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma)
+bool GPU_lamp_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma)
{
- if (srl && srl->light_override)
+ if (lamp->hide)
+ return false;
+ else if (srl && srl->light_override)
return BKE_group_object_exists(srl->light_override, lamp->ob);
else if (ma && ma->group)
return BKE_group_object_exists(ma->group, lamp->ob);
@@ -334,8 +340,8 @@ void GPU_material_bind(
for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) {
GPULamp *lamp = nlink->data;
- if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) &&
- GPU_lamp_override_visible(lamp, srl, material->ma))
+ if ((lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) &&
+ GPU_lamp_visible(lamp, srl, material->ma))
{
lamp->dynenergy = lamp->energy;
copy_v3_v3(lamp->dyncol, lamp->col);
@@ -398,9 +404,14 @@ void GPU_material_bind(
}
}
+GPUBuiltin GPU_get_material_builtins(GPUMaterial *material)
+{
+ return material->builtins;
+}
+
void GPU_material_bind_uniforms(
GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
- float autobumpscale, GPUParticleInfo *pi)
+ float autobumpscale, GPUParticleInfo *pi, float object_info[3])
{
if (material->pass) {
GPUShader *shader = GPU_pass_shader(material->pass);
@@ -449,6 +460,9 @@ void GPU_material_bind_uniforms(
if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) {
GPU_shader_uniform_vector(shader, material->partangvel, 3, 1, pi->angular_velocity);
}
+ if (material->builtins & GPU_OBJECT_INFO) {
+ GPU_shader_uniform_vector(shader, material->objectinfoloc, 3, 1, object_info);
+ }
}
}
@@ -609,7 +623,7 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
GPU_link(mat, "lamp_visibility_spot",
GPU_dynamic_uniform(&lamp->spotsi, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob),
- GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob),
+ GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTBLEND, lamp->ob),
inpr, visifac, &visifac);
}
@@ -1891,7 +1905,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv
GPU_material_output_link(mat, outlink);
- GPU_material_construct_end(mat, "matcap_pass");
+ gpu_material_construct_end(mat, "matcap_pass");
/* note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simple do not use
@@ -2044,7 +2058,7 @@ static void do_world_tex(GPUShadeInput *shi, struct World *wo, GPUNodeLink **hor
}
}
-static void GPU_material_old_world(struct GPUMaterial *mat, struct World *wo)
+static void gpu_material_old_world(struct GPUMaterial *mat, struct World *wo)
{
GPUShadeInput shi;
GPUShadeResult shr;
@@ -2112,17 +2126,18 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
mat->type = GPU_MATERIAL_TYPE_WORLD;
/* create nodes */
- if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes)
+ if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes) {
ntreeGPUMaterialNodes(wo->nodetree, mat, NODE_NEW_SHADING);
+ }
else {
- GPU_material_old_world(mat, wo);
+ gpu_material_old_world(mat, wo);
}
if (GPU_material_do_color_management(mat))
if (mat->outlink)
GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink);
- GPU_material_construct_end(mat, wo->id.name);
+ gpu_material_construct_end(mat, wo->id.name);
/* note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simple do not use
@@ -2188,7 +2203,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_open
if (mat->outlink)
GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink);
- GPU_material_construct_end(mat, ma->id.name);
+ gpu_material_construct_end(mat, ma->id.name);
/* note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simple do not use
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 58582232cd5..632b0cfee1b 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -29,109 +29,92 @@
* Interface for accessing gpu-related methods for selection. The semantics will be
* similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility.
*/
+#include <stdlib.h>
+
#include "GPU_select.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
-
+
#include "MEM_guardedalloc.h"
#include "DNA_userdef_types.h"
#include "BLI_utildefines.h"
-/* Ad hoc number of queries to allocate to skip doing many glGenQueries */
-#define ALLOC_QUERIES 200
-
-typedef struct GPUQueryState {
+#include "gpu_select_private.h"
+
+/* Internal algorithm used */
+enum {
+ /** GL_SELECT, legacy OpenGL selection */
+ ALGO_GL_LEGACY = 1,
+ /** glBegin/EndQuery(GL_SAMPLES_PASSED... ), `gpu_select_query.c`
+ * Only sets 4th component (ID) correctly. */
+ ALGO_GL_QUERY = 2,
+ /** Read depth buffer for every drawing pass and extract depths, `gpu_select_pick.c`
+ * Only sets 4th component (ID) correctly. */
+ ALGO_GL_PICK = 3,
+};
+
+typedef struct GPUSelectState {
/* To ignore selection id calls when not initialized */
bool select_is_active;
- /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */
- bool query_issued;
- /* array holding the OpenGL query identifiers */
- unsigned int *queries;
- /* array holding the id corresponding to each query */
- unsigned int *id;
- /* number of queries in *queries and *id */
- unsigned int num_of_queries;
- /* index to the next query to start */
- unsigned int active_query;
/* flag to cache user preference for occlusion based selection */
bool use_gpu_select;
- /* cache on initialization */
- unsigned int *buffer;
- /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/
- unsigned int bufsize;
/* mode of operation */
char mode;
- unsigned int index;
- int oldhits;
-} GPUQueryState;
+ /* internal algorithm for selection */
+ char algorithm;
+ /* allow GPU_select_begin/end without drawing */
+ bool use_cache;
+} GPUSelectState;
-static GPUQueryState g_query_state = {0};
+static GPUSelectState g_select_state = {0};
/**
* initialize and provide buffer for results
*/
-void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits)
+void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rcti *input, char mode, int oldhits)
{
- g_query_state.select_is_active = true;
- g_query_state.query_issued = false;
- g_query_state.active_query = 0;
- g_query_state.use_gpu_select = GPU_select_query_check_active();
- g_query_state.num_of_queries = 0;
- g_query_state.bufsize = bufsize;
- g_query_state.buffer = buffer;
- g_query_state.mode = mode;
- g_query_state.index = 0;
- g_query_state.oldhits = oldhits;
-
- if (!g_query_state.use_gpu_select) {
- glSelectBuffer(bufsize, (GLuint *)buffer);
- glRenderMode(GL_SELECT);
- glInitNames();
- glPushName(-1);
+ if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
+ /* In the case hits was '-1', don't start the second pass since it's not going to give useful results.
+ * As well as buffer overflow in 'gpu_select_query_load_id'. */
+ BLI_assert(oldhits != -1);
}
- else {
- float viewport[4];
-
- g_query_state.num_of_queries = ALLOC_QUERIES;
- g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries), "gpu selection queries");
- g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id), "gpu selection ids");
- glGenQueries(g_query_state.num_of_queries, g_query_state.queries);
+ g_select_state.select_is_active = true;
+ g_select_state.use_gpu_select = GPU_select_query_check_active();
+ g_select_state.mode = mode;
- glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT);
- /* disable writing to the framebuffer */
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-
- /* In order to save some fill rate we minimize the viewport using rect.
- * We need to get the region of the scissor so that our geometry doesn't
- * get rejected before the depth test. Should probably cull rect against
- * scissor for viewport but this is a rare case I think */
- glGetFloatv(GL_SCISSOR_BOX, viewport);
- if (!input || input->xmin == input->xmax) {
- glViewport(viewport[0], viewport[1], 24, 24);
- }
- else {
- glViewport(viewport[0], viewport[1], (int)(input->xmax - input->xmin), (int)(input->ymax - input->ymin));
- }
+ if (ELEM(g_select_state.mode, GPU_SELECT_PICK_ALL, GPU_SELECT_PICK_NEAREST)) {
+ g_select_state.algorithm = ALGO_GL_PICK;
+ }
+ else if (!g_select_state.use_gpu_select) {
+ g_select_state.algorithm = ALGO_GL_LEGACY;
+ }
+ else {
+ g_select_state.algorithm = ALGO_GL_QUERY;
+ }
- /* occlusion queries operates on fragments that pass tests and since we are interested on all
- * objects in the view frustum independently of their order, we need to disable the depth test */
- if (mode == GPU_SELECT_ALL) {
- glDisable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
+ switch (g_select_state.algorithm) {
+ case ALGO_GL_LEGACY:
+ {
+ g_select_state.use_cache = false;
+ glSelectBuffer(bufsize, (GLuint *)buffer);
+ glRenderMode(GL_SELECT);
+ glInitNames();
+ glPushName(-1);
+ break;
}
- else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) {
- glClear(GL_DEPTH_BUFFER_BIT);
- glEnable(GL_DEPTH_TEST);
- glDepthMask(GL_TRUE);
- glDepthFunc(GL_LEQUAL);
+ case ALGO_GL_QUERY:
+ {
+ g_select_state.use_cache = false;
+ gpu_select_query_begin((unsigned int (*)[4])buffer, bufsize / 4, input, mode, oldhits);
+ break;
}
- else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
- glEnable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
- glDepthFunc(GL_EQUAL);
+ default: /* ALGO_GL_PICK */
+ {
+ gpu_select_pick_begin((unsigned int (*)[4])buffer, bufsize / 4, input, mode);
+ break;
}
}
}
@@ -146,41 +129,24 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, c
bool GPU_select_load_id(unsigned int id)
{
/* if no selection mode active, ignore */
- if (!g_query_state.select_is_active)
+ if (!g_select_state.select_is_active)
return true;
- if (!g_query_state.use_gpu_select) {
- glLoadName(id);
- }
- else {
- if (g_query_state.query_issued) {
- glEndQuery(GL_SAMPLES_PASSED);
+ switch (g_select_state.algorithm) {
+ case ALGO_GL_LEGACY:
+ {
+ glLoadName(id);
+ return true;
}
- /* if required, allocate extra queries */
- if (g_query_state.active_query == g_query_state.num_of_queries) {
- g_query_state.num_of_queries += ALLOC_QUERIES;
- g_query_state.queries = MEM_reallocN(g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries));
- g_query_state.id = MEM_reallocN(g_query_state.id, g_query_state.num_of_queries * sizeof(*g_query_state.id));
- glGenQueries(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]);
+ case ALGO_GL_QUERY:
+ {
+ return gpu_select_query_load_id(id);
}
-
- glBeginQuery(GL_SAMPLES_PASSED, g_query_state.queries[g_query_state.active_query]);
- g_query_state.id[g_query_state.active_query] = id;
- g_query_state.active_query++;
- g_query_state.query_issued = true;
-
- if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS && g_query_state.index < g_query_state.oldhits) {
- if (g_query_state.buffer[g_query_state.index * 4 + 3] == id) {
- g_query_state.index++;
- return true;
- }
- else {
- return false;
- }
+ default: /* ALGO_GL_PICK */
+ {
+ return gpu_select_pick_load_id(id);
}
}
-
- return true;
}
/**
@@ -191,59 +157,27 @@ bool GPU_select_load_id(unsigned int id)
unsigned int GPU_select_end(void)
{
unsigned int hits = 0;
- if (!g_query_state.use_gpu_select) {
- glPopName();
- hits = glRenderMode(GL_RENDER);
- }
- else {
- int i;
- if (g_query_state.query_issued) {
- glEndQuery(GL_SAMPLES_PASSED);
+ switch (g_select_state.algorithm) {
+ case ALGO_GL_LEGACY:
+ {
+ glPopName();
+ hits = glRenderMode(GL_RENDER);
+ break;
}
-
- for (i = 0; i < g_query_state.active_query; i++) {
- unsigned int result;
- glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT, &result);
- if (result > 0) {
- if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
- int maxhits = g_query_state.bufsize / 4;
-
- if (hits < maxhits) {
- g_query_state.buffer[hits * 4] = 1;
- g_query_state.buffer[hits * 4 + 1] = 0xFFFF;
- g_query_state.buffer[hits * 4 + 2] = 0xFFFF;
- g_query_state.buffer[hits * 4 + 3] = g_query_state.id[i];
-
- hits++;
- }
- else {
- hits = -1;
- break;
- }
- }
- else {
- int j;
- /* search in buffer and make selected object first */
- for (j = 0; j < g_query_state.oldhits; j++) {
- if (g_query_state.buffer[j * 4 + 3] == g_query_state.id[i]) {
- g_query_state.buffer[j * 4 + 1] = 0;
- g_query_state.buffer[j * 4 + 2] = 0;
- }
- }
- break;
- }
- }
+ case ALGO_GL_QUERY:
+ {
+ hits = gpu_select_query_end();
+ break;
+ }
+ default: /* ALGO_GL_PICK */
+ {
+ hits = gpu_select_pick_end();
+ break;
}
-
- glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries);
- MEM_freeN(g_query_state.queries);
- MEM_freeN(g_query_state.id);
- glPopAttrib();
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
- g_query_state.select_is_active = false;
+ g_select_state.select_is_active = false;
return hits;
}
@@ -260,3 +194,41 @@ bool GPU_select_query_check_active(void)
GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE))));
}
+
+/* ----------------------------------------------------------------------------
+ * Caching
+ *
+ * Support multiple begin/end's as long as they are within the initial region.
+ * Currently only used by ALGO_GL_PICK.
+ */
+
+void GPU_select_cache_begin(void)
+{
+ /* validate on GPU_select_begin, clear if not supported */
+ BLI_assert(g_select_state.use_cache == false);
+ g_select_state.use_cache = true;
+ if (g_select_state.algorithm == ALGO_GL_PICK) {
+ gpu_select_pick_cache_begin();
+ }
+}
+
+void GPU_select_cache_load_id(void)
+{
+ BLI_assert(g_select_state.use_cache == true);
+ if (g_select_state.algorithm == ALGO_GL_PICK) {
+ gpu_select_pick_cache_load_id();
+ }
+}
+
+void GPU_select_cache_end(void)
+{
+ if (g_select_state.algorithm == ALGO_GL_PICK) {
+ gpu_select_pick_cache_end();
+ }
+ g_select_state.use_cache = false;
+}
+
+bool GPU_select_is_cached(void)
+{
+ return g_select_state.use_cache && gpu_select_pick_is_cached();
+}
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
new file mode 100644
index 00000000000..0a77420fa25
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -0,0 +1,744 @@
+/*
+ * ***** 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) 2017 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_select_pick.c
+ * \ingroup gpu
+ *
+ * Custom select code for picking small regions (not efficient for large regions).
+ * `gpu_select_pick_*` API.
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <float.h>
+
+#include "GPU_select.h"
+#include "GPU_extensions.h"
+#include "GPU_glew.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_rect.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "gpu_select_private.h"
+
+#include "BLI_strict_flags.h"
+
+/* #define DEBUG_PRINT */
+
+/* Alloc number for depths */
+#define ALLOC_DEPTHS 200
+
+/* Z-depth of cleared depth buffer */
+#define DEPTH_MAX 0xffffffff
+
+/* ----------------------------------------------------------------------------
+ * SubRectStride
+ */
+
+/* For looping over a sub-region of a rect, could be moved into 'rct.c'*/
+typedef struct SubRectStride {
+ unsigned int start; /* start here */
+ unsigned int span; /* read these */
+ unsigned int span_len; /* len times (read span 'len' times). */
+ unsigned int skip; /* skip those */
+} SubRectStride;
+
+/* we may want to change back to float if uint isn't well supported */
+typedef unsigned int depth_t;
+
+/**
+ * Calculate values needed for looping over a sub-region (smaller buffer within a larger buffer).
+ *
+ * 'src' must be bigger than 'dst'.
+ */
+static void rect_subregion_stride_calc(const rcti *src, const rcti *dst, SubRectStride *r_sub)
+{
+ const int src_x = BLI_rcti_size_x(src);
+ // const int src_y = BLI_rcti_size_y(src);
+ const int dst_x = BLI_rcti_size_x(dst);
+ const int dst_y = BLI_rcti_size_y(dst);
+ const int x = dst->xmin - src->xmin;
+ const int y = dst->ymin - src->ymin;
+
+ BLI_assert(src->xmin <= dst->xmin && src->ymin <= dst->ymin &&
+ src->ymax >= dst->ymax && src->ymax >= dst->ymax);
+ BLI_assert(x >= 0 && y >= 0);
+
+ r_sub->start = (unsigned int)((src_x * y) + x);
+ r_sub->span = (unsigned int)dst_x;
+ r_sub->span_len = (unsigned int)dst_y;
+ r_sub->skip = (unsigned int)(src_x - dst_x);
+}
+
+/**
+ * Ignore depth clearing as a change,
+ * only check if its been changed _and_ filled in (ignore clearing since XRAY does this).
+ */
+BLI_INLINE bool depth_is_filled(const depth_t *prev, const depth_t *curr)
+{
+ return (*prev != *curr) && (*curr != DEPTH_MAX);
+}
+
+/* ----------------------------------------------------------------------------
+ * DepthBufCache
+ *
+ * Result of reading glReadPixels,
+ * use for both cache and non-cached storage.
+ */
+
+/* store result of glReadPixels */
+typedef struct DepthBufCache {
+ struct DepthBufCache *next, *prev;
+ unsigned int id;
+ depth_t buf[0];
+} DepthBufCache;
+
+static DepthBufCache *depth_buf_malloc(unsigned int rect_len)
+{
+ DepthBufCache *rect = MEM_mallocN(sizeof(DepthBufCache) + sizeof(depth_t) * rect_len, __func__);
+ rect->id = SELECT_ID_NONE;
+ return rect;
+}
+
+static bool depth_buf_rect_depth_any(
+ const DepthBufCache *rect_depth,
+ unsigned int rect_len)
+{
+ const depth_t *curr = rect_depth->buf;
+ for (unsigned int i = 0; i < rect_len; i++, curr++) {
+ if (*curr != DEPTH_MAX) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool depth_buf_subrect_depth_any(
+ const DepthBufCache *rect_depth,
+ const SubRectStride *sub_rect)
+{
+ const depth_t *curr = rect_depth->buf + sub_rect->start;
+ for (unsigned int i = 0; i < sub_rect->span_len; i++) {
+ const depth_t *curr_end = curr + sub_rect->span;
+ for (; curr < curr_end; curr++, curr++) {
+ if (*curr != DEPTH_MAX) {
+ return true;
+ }
+ }
+ curr += sub_rect->skip;
+ }
+ return false;
+}
+
+static bool depth_buf_rect_depth_any_filled(
+ const DepthBufCache *rect_prev, const DepthBufCache *rect_curr,
+ unsigned int rect_len)
+{
+#if 0
+ return memcmp(rect_depth_a->buf, rect_depth_b->buf, rect_len * sizeof(depth_t)) != 0;
+#else
+ const depth_t *prev = rect_prev->buf;
+ const depth_t *curr = rect_curr->buf;
+ for (unsigned int i = 0; i < rect_len; i++, curr++, prev++) {
+ if (depth_is_filled(prev, curr)) {
+ return true;
+ }
+ }
+ return false;
+#endif
+}
+
+/**
+ * Both buffers are the same size, just check if the sub-rect contains any differences.
+ */
+static bool depth_buf_subrect_depth_any_filled(
+ const DepthBufCache *rect_src, const DepthBufCache *rect_dst,
+ const SubRectStride *sub_rect)
+{
+ /* same as above but different rect sizes */
+ const depth_t *prev = rect_src->buf + sub_rect->start;
+ const depth_t *curr = rect_dst->buf + sub_rect->start;
+ for (unsigned int i = 0; i < sub_rect->span_len; i++) {
+ const depth_t *curr_end = curr + sub_rect->span;
+ for (; curr < curr_end; prev++, curr++) {
+ if (depth_is_filled(prev, curr)) {
+ return true;
+ }
+ }
+ prev += sub_rect->skip;
+ curr += sub_rect->skip;
+ }
+ return false;
+}
+
+/* ----------------------------------------------------------------------------
+ * DepthID
+ *
+ * Internal structure for storing hits.
+ */
+
+typedef struct DepthID {
+ unsigned int id;
+ depth_t depth;
+} DepthID;
+
+static int depth_id_cmp(const void *v1, const void *v2)
+{
+ const DepthID *d1 = v1, *d2 = v2;
+ if (d1->id < d2->id) {
+ return -1;
+ }
+ else if (d1->id > d2->id) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int depth_cmp(const void *v1, const void *v2)
+{
+ const DepthID *d1 = v1, *d2 = v2;
+ if (d1->depth < d2->depth) {
+ return -1;
+ }
+ else if (d1->depth > d2->depth) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+/* depth sorting */
+typedef struct GPUPickState {
+ /* cache on initialization */
+ unsigned int (*buffer)[4];
+
+ /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/
+ unsigned int bufsize;
+ /* mode of operation */
+ char mode;
+
+ /* OpenGL drawing, never use when (is_cached == true). */
+ struct {
+ /* The current depth, accumulated as we draw */
+ DepthBufCache *rect_depth;
+ /* Scratch buffer, avoid allocs every time (when not caching) */
+ DepthBufCache *rect_depth_test;
+
+ /* Pass to glReadPixels (x, y, w, h) */
+ int clip_readpixels[4];
+
+ /* Set after first draw */
+ bool is_init;
+ unsigned int prev_id;
+ } gl;
+
+ /* src: data stored in 'cache' and 'gl',
+ * dst: use when cached region is smaller (where src -> dst isn't 1:1) */
+ struct {
+ rcti clip_rect;
+ unsigned int rect_len;
+ } src, dst;
+
+ /* Store cache between `GPU_select_cache_begin/end` */
+ bool use_cache;
+ bool is_cached;
+ struct {
+ /* Cleanup used for iterating over both source and destination buffers:
+ * src.clip_rect -> dst.clip_rect */
+ SubRectStride sub_rect;
+
+ /* List of DepthBufCache, sized of 'src.clip_rect' */
+ ListBase bufs;
+ } cache;
+
+ /* Pickign methods */
+ union {
+ /* GPU_SELECT_PICK_ALL */
+ struct {
+ DepthID *hits;
+ unsigned int hits_len;
+ unsigned int hits_len_alloc;
+ } all;
+
+ /* GPU_SELECT_PICK_NEAREST */
+ struct {
+ unsigned int *rect_id;
+ } nearest;
+ };
+} GPUPickState;
+
+
+static GPUPickState g_pick_state = {0};
+
+void gpu_select_pick_begin(
+ unsigned int (*buffer)[4], unsigned int bufsize,
+ const rcti *input, char mode)
+{
+ GPUPickState *ps = &g_pick_state;
+
+#ifdef DEBUG_PRINT
+ printf("%s: mode=%d, use_cache=%d, is_cache=%d\n", __func__, mode, ps->use_cache, ps->is_cached);
+#endif
+
+ ps->bufsize = bufsize;
+ ps->buffer = buffer;
+ ps->mode = mode;
+
+ const unsigned int rect_len = (unsigned int)(BLI_rcti_size_x(input) * BLI_rcti_size_y(input));
+ ps->dst.clip_rect = *input;
+ ps->dst.rect_len = rect_len;
+
+ /* Restrict OpenGL operations for when we don't have cache */
+ if (ps->is_cached == false) {
+
+ glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT);
+ /* disable writing to the framebuffer */
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+
+ if (mode == GPU_SELECT_PICK_ALL) {
+ glDepthFunc(GL_ALWAYS);
+ }
+ else {
+ glDepthFunc(GL_LEQUAL);
+ }
+
+ /* set just in case */
+ glPixelTransferf(GL_DEPTH_BIAS, 0.0);
+ glPixelTransferf(GL_DEPTH_SCALE, 1.0);
+
+ float viewport[4];
+ glGetFloatv(GL_SCISSOR_BOX, viewport);
+
+ ps->src.clip_rect = *input;
+ ps->src.rect_len = rect_len;
+
+ ps->gl.clip_readpixels[0] = (int)viewport[0];
+ ps->gl.clip_readpixels[1] = (int)viewport[1];
+ ps->gl.clip_readpixels[2] = BLI_rcti_size_x(&ps->src.clip_rect);
+ ps->gl.clip_readpixels[3] = BLI_rcti_size_y(&ps->src.clip_rect);
+
+ glViewport(UNPACK4(ps->gl.clip_readpixels));
+
+ /* It's possible we don't want to clear depth buffer,
+ * so existing elements are masked by current z-buffer. */
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ /* scratch buffer (read new values here) */
+ ps->gl.rect_depth_test = depth_buf_malloc(rect_len);
+ ps->gl.rect_depth = depth_buf_malloc(rect_len);
+
+ /* set initial 'far' value */
+#if 0
+ glReadPixels(UNPACK4(ps->gl.clip_readpixels), GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, ps->gl.rect_depth->buf);
+#else
+ for (unsigned int i = 0; i < rect_len; i++) {
+ ps->gl.rect_depth->buf[i] = DEPTH_MAX;
+ }
+#endif
+
+ ps->gl.is_init = false;
+ ps->gl.prev_id = 0;
+ }
+ else {
+ /* Using cache (ps->is_cached == true) */
+ /* src.clip_rect -> dst.clip_rect */
+ rect_subregion_stride_calc(&ps->src.clip_rect, &ps->dst.clip_rect, &ps->cache.sub_rect);
+ BLI_assert(ps->gl.rect_depth == NULL);
+ BLI_assert(ps->gl.rect_depth_test == NULL);
+ }
+
+ if (mode == GPU_SELECT_PICK_ALL) {
+ ps->all.hits = MEM_mallocN(sizeof(*ps->all.hits) * ALLOC_DEPTHS, __func__);
+ ps->all.hits_len = 0;
+ ps->all.hits_len_alloc = ALLOC_DEPTHS;
+ }
+ else {
+ /* Set to 0xff for SELECT_ID_NONE */
+ ps->nearest.rect_id = MEM_mallocN(sizeof(unsigned int) * ps->dst.rect_len, __func__);
+ memset(ps->nearest.rect_id, 0xff, sizeof(unsigned int) * ps->dst.rect_len);
+ }
+}
+
+/**
+ * Given 2x depths, we know are different - update the depth information
+ * use for both cached/uncached depth buffers.
+ */
+static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr)
+{
+ GPUPickState *ps = &g_pick_state;
+ const unsigned int id = rect_curr->id;
+ /* find the best depth for this pass and store in 'all.hits' */
+ depth_t depth_best = DEPTH_MAX;
+
+#define EVAL_TEST() \
+ if (depth_best > *curr) { \
+ depth_best = *curr; \
+ } ((void)0)
+
+ if (ps->is_cached == false) {
+ const depth_t *curr = rect_curr->buf;
+ BLI_assert(ps->src.rect_len == ps->dst.rect_len);
+ const unsigned int rect_len = ps->src.rect_len;
+ for (unsigned int i = 0; i < rect_len; i++, curr++) {
+ EVAL_TEST();
+ }
+ }
+ else {
+ /* same as above but different rect sizes */
+ const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start;
+ for (unsigned int i = 0; i < ps->cache.sub_rect.span_len; i++) {
+ const depth_t *curr_end = curr + ps->cache.sub_rect.span;
+ for (; curr < curr_end; curr++) {
+ EVAL_TEST();
+ }
+ curr += ps->cache.sub_rect.skip;
+ }
+ }
+
+#undef EVAL_TEST
+
+ /* ensure enough space */
+ if (UNLIKELY(ps->all.hits_len == ps->all.hits_len_alloc)) {
+ ps->all.hits_len_alloc += ALLOC_DEPTHS;
+ ps->all.hits = MEM_reallocN(ps->all.hits, ps->all.hits_len_alloc * sizeof(*ps->all.hits));
+ }
+ DepthID *d = &ps->all.hits[ps->all.hits_len++];
+ d->id = id;
+ d->depth = depth_best;
+}
+
+static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, const DepthBufCache *rect_curr)
+{
+ GPUPickState *ps = &g_pick_state;
+ const unsigned int id = rect_curr->id;
+ /* keep track each pixels ID in 'nearest.rect_id' */
+ if (id != SELECT_ID_NONE) {
+ unsigned int *id_ptr = ps->nearest.rect_id;
+
+ /* Check against DEPTH_MAX because XRAY will clear the buffer,
+ * so previously set values will become unset.
+ * In this case just leave those id's left as-is. */
+#define EVAL_TEST() \
+ if (depth_is_filled(prev, curr)) { \
+ *id_ptr = id; \
+ } ((void)0)
+
+ if (ps->is_cached == false) {
+ const depth_t *prev = rect_prev->buf;
+ const depth_t *curr = rect_curr->buf;
+ BLI_assert(ps->src.rect_len == ps->dst.rect_len);
+ const unsigned int rect_len = ps->src.rect_len;
+ for (unsigned int i = 0; i < rect_len; i++, curr++, prev++, id_ptr++) {
+ EVAL_TEST();
+ }
+ }
+ else {
+ /* same as above but different rect sizes */
+ const depth_t *prev = rect_prev->buf + ps->cache.sub_rect.start;
+ const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start;
+ for (unsigned int i = 0; i < ps->cache.sub_rect.span_len; i++) {
+ const depth_t *curr_end = curr + ps->cache.sub_rect.span;
+ for (; curr < curr_end; prev++, curr++, id_ptr++) {
+ EVAL_TEST();
+ }
+ prev += ps->cache.sub_rect.skip;
+ curr += ps->cache.sub_rect.skip;
+ }
+ }
+
+#undef EVAL_TEST
+ }
+}
+
+
+bool gpu_select_pick_load_id(unsigned int id)
+{
+ GPUPickState *ps = &g_pick_state;
+ if (ps->gl.is_init) {
+ const unsigned int rect_len = ps->src.rect_len;
+ glReadPixels(UNPACK4(ps->gl.clip_readpixels), GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, ps->gl.rect_depth_test->buf);
+ /* perform initial check since most cases the array remains unchanged */
+
+ bool do_pass = false;
+ if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
+ if (depth_buf_rect_depth_any(ps->gl.rect_depth_test, rect_len)) {
+ ps->gl.rect_depth_test->id = ps->gl.prev_id;
+ gpu_select_load_id_pass_all(ps->gl.rect_depth_test);
+ do_pass = true;
+ }
+ }
+ else {
+ if (depth_buf_rect_depth_any_filled(ps->gl.rect_depth, ps->gl.rect_depth_test, rect_len)) {
+ ps->gl.rect_depth_test->id = ps->gl.prev_id;
+ gpu_select_load_id_pass_nearest(ps->gl.rect_depth, ps->gl.rect_depth_test);
+ do_pass = true;
+ }
+ }
+
+ if (do_pass) {
+ /* Store depth in cache */
+ if (ps->use_cache) {
+ BLI_addtail(&ps->cache.bufs, ps->gl.rect_depth);
+ ps->gl.rect_depth = depth_buf_malloc(ps->src.rect_len);
+ }
+
+ SWAP(DepthBufCache *, ps->gl.rect_depth, ps->gl.rect_depth_test);
+
+ if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
+ /* we want new depths every time */
+ glClear(GL_DEPTH_BUFFER_BIT);
+ }
+ }
+ }
+
+ ps->gl.is_init = true;
+ ps->gl.prev_id = id;
+
+ return true;
+}
+
+unsigned int gpu_select_pick_end(void)
+{
+ GPUPickState *ps = &g_pick_state;
+
+#ifdef DEBUG_PRINT
+ printf("%s\n", __func__);
+#endif
+
+ if (ps->is_cached == false) {
+ if (ps->gl.is_init) {
+ /* force finishing last pass */
+ gpu_select_pick_load_id(ps->gl.prev_id);
+ }
+
+ glPopAttrib();
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+
+ /* assign but never free directly since it may be in cache */
+ DepthBufCache *rect_depth_final;
+
+ /* Store depth in cache */
+ if (ps->use_cache && !ps->is_cached) {
+ BLI_addtail(&ps->cache.bufs, ps->gl.rect_depth);
+ ps->gl.rect_depth = NULL;
+ rect_depth_final = ps->cache.bufs.last;
+ }
+ else if (ps->is_cached) {
+ rect_depth_final = ps->cache.bufs.last;
+ }
+ else {
+ /* common case, no cache */
+ rect_depth_final = ps->gl.rect_depth;
+ }
+
+ unsigned int maxhits = g_pick_state.bufsize;
+ DepthID *depth_data;
+ unsigned int depth_data_len = 0;
+
+ if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
+ depth_data = ps->all.hits;
+ depth_data_len = ps->all.hits_len;
+ /* move ownership */
+ ps->all.hits = NULL;
+ ps->all.hits_len = 0;
+ ps->all.hits_len_alloc = 0;
+ }
+ else {
+ /* GPU_SELECT_PICK_NEAREST */
+
+ /* Over alloc (unlikely we have as many depths as pixels) */
+ unsigned int depth_data_len_first_pass = 0;
+ depth_data = MEM_mallocN(ps->dst.rect_len * sizeof(*depth_data), __func__);
+
+ /* Partially de-duplicating copy,
+ * when contiguous ID's are found - update their closest depth.
+ * This isn't essential but means there is less data to sort. */
+
+#define EVAL_TEST(i_src, i_dst) \
+ { \
+ const unsigned int id = ps->nearest.rect_id[i_dst]; \
+ if (id != SELECT_ID_NONE) { \
+ const depth_t depth = rect_depth_final->buf[i_src]; \
+ if (depth_last == NULL || depth_last->id != id) { \
+ DepthID *d = &depth_data[depth_data_len_first_pass++]; \
+ d->id = id; \
+ d->depth = depth; \
+ } \
+ else if (depth_last->depth > depth) { \
+ depth_last->depth = depth; \
+ } \
+ } \
+ } ((void)0)
+
+ {
+ DepthID *depth_last = NULL;
+ if (ps->is_cached == false) {
+ for (unsigned int i = 0; i < ps->src.rect_len; i++) {
+ EVAL_TEST(i, i);
+ }
+ }
+ else {
+ /* same as above but different rect sizes */
+ unsigned int i_src = ps->cache.sub_rect.start, i_dst = 0;
+ for (unsigned int j = 0; j < ps->cache.sub_rect.span_len; j++) {
+ const unsigned int i_src_end = i_src + ps->cache.sub_rect.span;
+ for (; i_src < i_src_end; i_src++, i_dst++) {
+ EVAL_TEST(i_src, i_dst);
+ }
+ i_src += ps->cache.sub_rect.skip;
+ }
+ }
+ }
+
+#undef EVAL_TEST
+
+ qsort(depth_data, depth_data_len_first_pass, sizeof(DepthID), depth_id_cmp);
+
+ /* Sort by ID's then keep the best depth for each ID */
+ depth_data_len = 0;
+ {
+ DepthID *depth_last = NULL;
+ for (unsigned int i = 0; i < depth_data_len_first_pass; i++) {
+ if (depth_last == NULL || depth_last->id != depth_data[i].id) {
+ depth_last = &depth_data[depth_data_len++];
+ *depth_last = depth_data[i];
+ }
+ else if (depth_last->depth > depth_data[i].depth) {
+ depth_last->depth = depth_data[i].depth;
+ }
+ }
+ }
+ }
+
+ /* Finally sort each unique (id, depth) pair by depth
+ * so the final hit-list is sorted by depth (nearest first) */
+ unsigned int hits = 0;
+
+ if (depth_data_len > maxhits) {
+ hits = (unsigned int)-1;
+ }
+ else {
+ /* leave sorting up to the caller */
+ qsort(depth_data, depth_data_len, sizeof(DepthID), depth_cmp);
+
+ for (unsigned int i = 0; i < depth_data_len; i++) {
+#ifdef DEBUG_PRINT
+ printf(" hit: %u: depth %u\n", depth_data[i].id, depth_data[i].depth);
+#endif
+ /* first 3 are dummy values */
+ g_pick_state.buffer[hits][0] = 1;
+ g_pick_state.buffer[hits][1] = 0x0; /* depth_data[i].depth; */ /* unused */
+ g_pick_state.buffer[hits][2] = 0x0; /* z-far is currently never used. */
+ g_pick_state.buffer[hits][3] = depth_data[i].id;
+ hits++;
+ }
+ BLI_assert(hits < maxhits);
+ }
+
+ MEM_freeN(depth_data);
+
+ MEM_SAFE_FREE(ps->gl.rect_depth);
+ MEM_SAFE_FREE(ps->gl.rect_depth_test);
+
+ if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
+ /* 'hits' already freed as 'depth_data' */
+ }
+ else {
+ MEM_freeN(ps->nearest.rect_id);
+ ps->nearest.rect_id = NULL;
+ }
+
+ if (ps->use_cache) {
+ ps->is_cached = true;
+ }
+
+ return hits;
+}
+
+/* ----------------------------------------------------------------------------
+ * Caching
+ *
+ * Support multiple begin/end's reusing depth buffers.
+ */
+
+void gpu_select_pick_cache_begin(void)
+{
+ BLI_assert(g_pick_state.use_cache == false);
+#ifdef DEBUG_PRINT
+ printf("%s\n", __func__);
+#endif
+ g_pick_state.use_cache = true;
+ g_pick_state.is_cached = false;
+}
+
+void gpu_select_pick_cache_end(void)
+{
+#ifdef DEBUG_PRINT
+ printf("%s: with %d buffers\n", __func__, BLI_listbase_count(&g_pick_state.cache.bufs));
+#endif
+ g_pick_state.use_cache = false;
+ g_pick_state.is_cached = false;
+
+ BLI_freelistN(&g_pick_state.cache.bufs);
+}
+
+/* is drawing needed? */
+bool gpu_select_pick_is_cached(void)
+{
+ return g_pick_state.is_cached;
+}
+
+void gpu_select_pick_cache_load_id(void)
+{
+ BLI_assert(g_pick_state.is_cached == true);
+ GPUPickState *ps = &g_pick_state;
+#ifdef DEBUG_PRINT
+ printf("%s (building depth from cache)\n", __func__);
+#endif
+ for (DepthBufCache *rect_depth = ps->cache.bufs.first; rect_depth; rect_depth = rect_depth->next) {
+ if (rect_depth->next != NULL) {
+ /* we know the buffers differ, but this sub-region may not.
+ * double check before adding an id-pass */
+ if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
+ if (depth_buf_subrect_depth_any(rect_depth->next, &ps->cache.sub_rect)) {
+ gpu_select_load_id_pass_all(rect_depth->next);
+ }
+ }
+ else {
+ if (depth_buf_subrect_depth_any_filled(rect_depth, rect_depth->next, &ps->cache.sub_rect)) {
+ gpu_select_load_id_pass_nearest(rect_depth, rect_depth->next);
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h
new file mode 100644
index 00000000000..8935bd7b253
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_select_private.h
@@ -0,0 +1,53 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Antony Riakiotakis.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_select_private.h
+ * \ingroup gpu
+ *
+ * Selection implementations.
+ */
+
+#ifndef __GPU_SELECT_PRIVATE_H__
+#define __GPU_SELECT_PRIVATE_H__
+
+/* gpu_select_pick */
+void gpu_select_pick_begin(unsigned int (*buffer)[4], unsigned int bufsize, const rcti *input, char mode);
+bool gpu_select_pick_load_id(unsigned int id);
+unsigned int gpu_select_pick_end(void);
+
+void gpu_select_pick_cache_begin(void);
+void gpu_select_pick_cache_end(void);
+bool gpu_select_pick_is_cached(void);
+void gpu_select_pick_cache_load_id(void);
+
+/* gpu_select_sample_query */
+void gpu_select_query_begin(unsigned int (*buffer)[4], unsigned int bufsize, const rcti *input, char mode, int oldhits);
+bool gpu_select_query_load_id(unsigned int id);
+unsigned int gpu_select_query_end(void);
+
+
+#define SELECT_ID_NONE ((unsigned int)0xffffffff)
+
+#endif /* __GPU_SELECT_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c
new file mode 100644
index 00000000000..3d589986281
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_select_sample_query.c
@@ -0,0 +1,213 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Antony Riakiotakis.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_select_sample_query.c
+ * \ingroup gpu
+ *
+ * Interface for accessing gpu-related methods for selection. The semantics will be
+ * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility.
+ */
+
+#include <stdlib.h>
+
+#include "GPU_select.h"
+#include "GPU_extensions.h"
+#include "GPU_glew.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_rect.h"
+
+#include "BLI_utildefines.h"
+
+#include "gpu_select_private.h"
+
+
+/* Ad hoc number of queries to allocate to skip doing many glGenQueries */
+#define ALLOC_QUERIES 200
+
+typedef struct GPUQueryState {
+ /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */
+ bool query_issued;
+ /* array holding the OpenGL query identifiers */
+ unsigned int *queries;
+ /* array holding the id corresponding to each query */
+ unsigned int *id;
+ /* number of queries in *queries and *id */
+ unsigned int num_of_queries;
+ /* index to the next query to start */
+ unsigned int active_query;
+ /* cache on initialization */
+ unsigned int (*buffer)[4];
+ /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/
+ unsigned int bufsize;
+ /* mode of operation */
+ char mode;
+ unsigned int index;
+ int oldhits;
+} GPUQueryState;
+
+static GPUQueryState g_query_state = {0};
+
+
+void gpu_select_query_begin(
+ unsigned int (*buffer)[4], unsigned int bufsize,
+ const rcti *input, char mode,
+ int oldhits)
+{
+ float viewport[4];
+
+ g_query_state.query_issued = false;
+ g_query_state.active_query = 0;
+ g_query_state.num_of_queries = 0;
+ g_query_state.bufsize = bufsize;
+ g_query_state.buffer = buffer;
+ g_query_state.mode = mode;
+ g_query_state.index = 0;
+ g_query_state.oldhits = oldhits;
+
+ g_query_state.num_of_queries = ALLOC_QUERIES;
+
+ g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries), "gpu selection queries");
+ g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id), "gpu selection ids");
+ glGenQueries(g_query_state.num_of_queries, g_query_state.queries);
+
+ glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT);
+ /* disable writing to the framebuffer */
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ /* In order to save some fill rate we minimize the viewport using rect.
+ * We need to get the region of the scissor so that our geometry doesn't
+ * get rejected before the depth test. Should probably cull rect against
+ * scissor for viewport but this is a rare case I think */
+ glGetFloatv(GL_SCISSOR_BOX, viewport);
+ glViewport(viewport[0], viewport[1], BLI_rcti_size_x(input), BLI_rcti_size_y(input));
+
+ /* occlusion queries operates on fragments that pass tests and since we are interested on all
+ * objects in the view frustum independently of their order, we need to disable the depth test */
+ if (mode == GPU_SELECT_ALL) {
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ }
+ else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) {
+ glClear(GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+ glDepthFunc(GL_LEQUAL);
+ }
+ else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ glDepthFunc(GL_EQUAL);
+ }
+}
+
+bool gpu_select_query_load_id(unsigned int id)
+{
+ if (g_query_state.query_issued) {
+ glEndQuery(GL_SAMPLES_PASSED);
+ }
+ /* if required, allocate extra queries */
+ if (g_query_state.active_query == g_query_state.num_of_queries) {
+ g_query_state.num_of_queries += ALLOC_QUERIES;
+ g_query_state.queries = MEM_reallocN(g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries));
+ g_query_state.id = MEM_reallocN(g_query_state.id, g_query_state.num_of_queries * sizeof(*g_query_state.id));
+ glGenQueries(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]);
+ }
+
+ glBeginQuery(GL_SAMPLES_PASSED, g_query_state.queries[g_query_state.active_query]);
+ g_query_state.id[g_query_state.active_query] = id;
+ g_query_state.active_query++;
+ g_query_state.query_issued = true;
+
+ if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) {
+ /* Second pass should never run if first pass fails, can read past 'bufsize' in this case. */
+ BLI_assert(g_query_state.oldhits != -1);
+ if (g_query_state.index < g_query_state.oldhits) {
+ if (g_query_state.buffer[g_query_state.index][3] == id) {
+ g_query_state.index++;
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+unsigned int gpu_select_query_end(void)
+{
+ int i;
+
+ unsigned int hits = 0;
+ const unsigned int maxhits = g_query_state.bufsize;
+
+ if (g_query_state.query_issued) {
+ glEndQuery(GL_SAMPLES_PASSED);
+ }
+
+ for (i = 0; i < g_query_state.active_query; i++) {
+ unsigned int result;
+ glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT, &result);
+ if (result > 0) {
+ if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
+
+ if (hits < maxhits) {
+ g_query_state.buffer[hits][0] = 1;
+ g_query_state.buffer[hits][1] = 0xFFFF;
+ g_query_state.buffer[hits][2] = 0xFFFF;
+ g_query_state.buffer[hits][3] = g_query_state.id[i];
+
+ hits++;
+ }
+ else {
+ hits = -1;
+ break;
+ }
+ }
+ else {
+ int j;
+ /* search in buffer and make selected object first */
+ for (j = 0; j < g_query_state.oldhits; j++) {
+ if (g_query_state.buffer[j][3] == g_query_state.id[i]) {
+ g_query_state.buffer[j][1] = 0;
+ g_query_state.buffer[j][2] = 0;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries);
+ MEM_freeN(g_query_state.queries);
+ MEM_freeN(g_query_state.id);
+ glPopAttrib();
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ return hits;
+}
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 14f2764b009..b579f87698c 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -39,6 +39,7 @@
#include "GPU_glew.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
+#include "GPU_material.h"
/* TODO(sergey): Find better default values for this constants. */
#define MAX_DEFINE_LENGTH 1024
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 54f0003c086..1c97c2ce811 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -79,7 +79,7 @@ static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixel
return pixels;
}
-static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
+static void gpu_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
{
void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels");
@@ -193,7 +193,7 @@ static GPUTexture *GPU_texture_create_nD(
pixels ? pixels : fpixels);
if (tex->w > w) {
- GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1);
+ gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1);
}
}
}
@@ -210,10 +210,12 @@ static GPUTexture *GPU_texture_create_nD(
glTexSubImage2D(tex->target, 0, 0, 0, w, h,
format, type, pixels ? pixels : fpixels);
- if (tex->w > w)
- GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h);
- if (tex->h > h)
- GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h);
+ if (tex->w > w) {
+ gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h);
+ }
+ if (tex->h > h) {
+ gpu_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h);
+ }
}
}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
index 054a2f795ee..f19ff4ec65a 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
@@ -27,8 +27,7 @@ vec3 calculate_view_space_normal(in vec3 viewposition)
{
vec3 normal = cross(normalize(dFdx(viewposition)),
ssao_params.w * normalize(dFdy(viewposition)));
- normalize(normal);
- return normal;
+ return normalize(normal);
}
float calculate_ssao_factor(float depth)
@@ -76,7 +75,7 @@ float calculate_ssao_factor(float depth)
float f = dot(dir, normal);
/* use minor bias here to avoid self shadowing */
- if (f > 0.05 * len + 0.0001)
+ if (f > 0.05 * len)
factor += f * 1.0 / (len * (1.0 + len * len * ssao_params.z));
}
}
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 4416b6494f9..3dbecc58a7e 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -403,7 +403,7 @@ void math_modulo(float val1, float val2, out float outval)
/* change sign to match C convention, mod in GLSL will take absolute for negative numbers,
* see https://www.opengl.org/sdk/docs/man/html/mod.xhtml */
- outval = (val1 > 0.0) ? outval : -outval;
+ outval = (val1 > 0.0) ? outval : outval - val2;
}
void math_abs(float val1, out float outval)
@@ -1358,7 +1358,7 @@ void mtex_cube_map_refl_from_refldir(
samplerCube ima, vec3 reflecteddirection, out float value, out vec4 color)
{
color = textureCube(ima, reflecteddirection);
- value = 1.0;
+ value = color.a;
}
void mtex_cube_map_refl(
@@ -2378,11 +2378,19 @@ void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
/*********** NEW SHADER UTILITIES **************/
-float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
+float fresnel_dielectric_0(float eta)
+{
+ /* compute fresnel reflactance at normal incidence => cosi = 1.0 */
+ float A = (eta - 1.0) / (eta + 1.0);
+
+ return A * A;
+}
+
+float fresnel_dielectric_cos(float cosi, float eta)
{
/* compute fresnel reflectance without explicitly computing
* the refracted direction */
- float c = abs(dot(Incoming, Normal));
+ float c = abs(cosi);
float g = eta * eta - 1.0 + c * c;
float result;
@@ -2399,6 +2407,13 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
return result;
}
+float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
+{
+ /* compute fresnel reflectance without explicitly computing
+ * the refracted direction */
+ return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
+}
+
float hypot(float x, float y)
{
return sqrt(x * x + y * y);
@@ -2492,6 +2507,57 @@ float floorfrac(float x, out int i)
return x - i;
}
+
+/* Principled BSDF operations */
+
+float sqr(float a)
+{
+ return a*a;
+}
+
+float schlick_fresnel(float u)
+{
+ float m = clamp(1.0 - u, 0.0, 1.0);
+ float m2 = m * m;
+ return m2 * m2 * m; // pow(m,5)
+}
+
+float GTR1(float NdotH, float a)
+{
+ if (a >= 1.0) return M_1_PI;
+ float a2 = a*a;
+ float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
+ return (a2 - 1.0) / (M_PI * log(a2) * t);
+}
+
+float GTR2(float NdotH, float a)
+{
+ float a2 = a*a;
+ float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
+ return a2 / (M_PI * t*t);
+}
+
+float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
+{
+ return 1.0 / (M_PI * ax*ay * sqr(sqr(HdotX / ax) + sqr(HdotY / ay) + NdotH*NdotH));
+}
+
+float smithG_GGX(float NdotV, float alphaG)
+{
+ float a = alphaG*alphaG;
+ float b = NdotV*NdotV;
+ return 1.0 / (NdotV + sqrt(a + b - a * b));
+}
+
+vec3 rotate_vector(vec3 p, vec3 n, float theta) {
+ return (
+ p * cos(theta) + cross(n, p) *
+ sin(theta) + n * dot(p, n) *
+ (1.0 - cos(theta))
+ );
+}
+
+
/*********** NEW SHADER NODES ***************/
#define NUM_LIGHTS 3
@@ -2553,6 +2619,125 @@ void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out vec4 resu
node_bsdf_diffuse(color, 0.0, N, result);
}
+void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
+ float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
+ float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result)
+{
+ /* ambient light */
+ // TODO: set ambient light to an appropriate value
+ vec3 L = mix(0.1, 0.03, metallic) * mix(base_color.rgb, subsurface_color.rgb, subsurface * (1.0 - metallic));
+
+ float eta = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
+
+ /* set the viewing vector */
+ vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? -normalize(I) : vec3(0.0, 0.0, 1.0);
+
+ /* get the tangent */
+ vec3 Tangent = T;
+ if (T == vec3(0.0)) {
+ // if no tangent is set, use a default tangent
+ if(N.x != N.y || N.x != N.z) {
+ Tangent = vec3(N.z-N.y, N.x-N.z, N.y-N.x); // (1,1,1) x N
+ }
+ else {
+ Tangent = vec3(N.z-N.y, N.x+N.z, -N.y-N.x); // (-1,1,1) x N
+ }
+ }
+
+ /* rotate tangent */
+ if (anisotropic_rotation != 0.0) {
+ Tangent = rotate_vector(Tangent, N, anisotropic_rotation * 2.0 * M_PI);
+ }
+
+ /* calculate the tangent and bitangent */
+ vec3 Y = normalize(cross(N, Tangent));
+ vec3 X = cross(Y, N);
+
+ /* fresnel normalization parameters */
+ float F0 = fresnel_dielectric_0(eta);
+ float F0_norm = 1.0 / (1.0 - F0);
+
+ /* directional lights */
+ for (int i = 0; i < NUM_LIGHTS; i++) {
+ vec3 light_position_world = gl_LightSource[i].position.xyz;
+ vec3 light_position = normalize(light_position_world);
+
+ vec3 H = normalize(light_position + V);
+
+ vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
+ vec3 light_specular = gl_LightSource[i].specular.rgb;
+
+ float NdotL = dot(N, light_position);
+ float NdotV = dot(N, V);
+ float LdotH = dot(light_position, H);
+
+ vec3 diffuse_and_specular_bsdf = vec3(0.0);
+ if (NdotL >= 0.0 && NdotV >= 0.0) {
+ float NdotH = dot(N, H);
+
+ float Cdlum = 0.3 * base_color.r + 0.6 * base_color.g + 0.1 * base_color.b; // luminance approx.
+
+ vec3 Ctint = Cdlum > 0 ? base_color.rgb / Cdlum : vec3(1.0); // normalize lum. to isolate hue+sat
+ vec3 Cspec0 = mix(specular * 0.08 * mix(vec3(1.0), Ctint, specular_tint), base_color.rgb, metallic);
+ vec3 Csheen = mix(vec3(1.0), Ctint, sheen_tint);
+
+ // Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
+ // and mix in diffuse retro-reflection based on roughness
+
+ float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV);
+ float Fd90 = 0.5 + 2.0 * LdotH*LdotH * roughness;
+ float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV);
+
+ // Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf
+ // 1.25 scale is used to (roughly) preserve albedo
+ // Fss90 used to "flatten" retroreflection based on roughness
+ float Fss90 = LdotH*LdotH * roughness;
+ float Fss = mix(1.0, Fss90, FL) * mix(1.0, Fss90, FV);
+ float ss = 1.25 * (Fss * (1.0 / (NdotL + NdotV) - 0.5) + 0.5);
+
+ // specular
+ float aspect = sqrt(1.0 - anisotropic * 0.9);
+ float a = sqr(roughness);
+ float ax = max(0.001, a / aspect);
+ float ay = max(0.001, a * aspect);
+ float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay); //GTR2(NdotH, a);
+ float FH = (fresnel_dielectric_cos(LdotH, eta) - F0) * F0_norm;
+ vec3 Fs = mix(Cspec0, vec3(1.0), FH);
+ float roughg = sqr(roughness * 0.5 + 0.5);
+ float Gs = smithG_GGX(NdotL, roughg) * smithG_GGX(NdotV, roughg);
+
+ // sheen
+ vec3 Fsheen = schlick_fresnel(LdotH) * sheen * Csheen;
+
+ vec3 diffuse_bsdf = (mix(Fd * base_color.rgb, ss * subsurface_color.rgb, subsurface) + Fsheen) * light_diffuse;
+ vec3 specular_bsdf = Gs * Fs * Ds * light_specular;
+ diffuse_and_specular_bsdf = diffuse_bsdf * (1.0 - metallic) + specular_bsdf;
+ }
+ diffuse_and_specular_bsdf *= max(NdotL, 0.0);
+
+ float CNdotL = dot(CN, light_position);
+ float CNdotV = dot(CN, V);
+
+ vec3 clearcoat_bsdf = vec3(0.0);
+ if (CNdotL >= 0.0 && CNdotV >= 0.0 && clearcoat > 0.0) {
+ float CNdotH = dot(CN, H);
+ //float FH = schlick_fresnel(LdotH);
+
+ // clearcoat (ior = 1.5 -> F0 = 0.04)
+ float Dr = GTR1(CNdotH, sqr(clearcoat_roughness));
+ float Fr = fresnel_dielectric_cos(LdotH, 1.5); //mix(0.04, 1.0, FH);
+ float Gr = smithG_GGX(CNdotL, 0.25) * smithG_GGX(CNdotV, 0.25);
+
+ clearcoat_bsdf = clearcoat * Gr * Fr * Dr * vec3(0.25) * light_specular;
+ }
+ clearcoat_bsdf *= max(CNdotL, 0.0);
+
+ L += diffuse_and_specular_bsdf + clearcoat_bsdf;
+ }
+
+ result = vec4(L, 1.0);
+}
+
void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result)
{
node_bsdf_diffuse(color, 0.0, N, result);
@@ -2846,10 +3031,10 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bi
float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0);
float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
- if(min_dist >= mortar_size) {
+ if (min_dist >= mortar_size) {
return vec2(tint, 0.0);
}
- else if(mortar_smooth == 0.0) {
+ else if (mortar_smooth == 0.0) {
return vec2(tint, 1.0);
}
else {
@@ -2931,15 +3116,17 @@ void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha)
}
void node_tex_image_box(vec3 texco,
- vec3 nob,
+ vec3 N,
sampler2D ima,
float blend,
out vec4 color,
out float alpha)
{
+ vec3 signed_N = N;
+
/* project from direction vector to barycentric coordinates in triangles */
- nob = vec3(abs(nob.x), abs(nob.y), abs(nob.z));
- nob /= (nob.x + nob.y + nob.z);
+ N = vec3(abs(N.x), abs(N.y), abs(N.z));
+ N /= (N.x + N.y + N.z);
/* basic idea is to think of this as a triangle, each corner representing
* one of the 3 faces of the cube. in the corners we have single textures,
@@ -2955,37 +3142,37 @@ void node_tex_image_box(vec3 texco,
float limit = 0.5 * (1.0 + blend);
/* first test for corners with single texture */
- if (nob.x > limit * (nob.x + nob.y) && nob.x > limit * (nob.x + nob.z)) {
+ if (N.x > limit * (N.x + N.y) && N.x > limit * (N.x + N.z)) {
weight.x = 1.0;
}
- else if (nob.y > limit * (nob.x + nob.y) && nob.y > limit * (nob.y + nob.z)) {
+ else if (N.y > limit * (N.x + N.y) && N.y > limit * (N.y + N.z)) {
weight.y = 1.0;
}
- else if (nob.z > limit * (nob.x + nob.z) && nob.z > limit * (nob.y + nob.z)) {
+ else if (N.z > limit * (N.x + N.z) && N.z > limit * (N.y + N.z)) {
weight.z = 1.0;
}
else if (blend > 0.0) {
/* in case of blending, test for mixes between two textures */
- if (nob.z < (1.0 - limit) * (nob.y + nob.x)) {
- weight.x = nob.x / (nob.x + nob.y);
+ if (N.z < (1.0 - limit) * (N.y + N.x)) {
+ weight.x = N.x / (N.x + N.y);
weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
weight.y = 1.0 - weight.x;
}
- else if (nob.x < (1.0 - limit) * (nob.y + nob.z)) {
- weight.y = nob.y / (nob.y + nob.z);
+ else if (N.x < (1.0 - limit) * (N.y + N.z)) {
+ weight.y = N.y / (N.y + N.z);
weight.y = clamp((weight.y - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
weight.z = 1.0 - weight.y;
}
- else if (nob.y < (1.0 - limit) * (nob.x + nob.z)) {
- weight.x = nob.x / (nob.x + nob.z);
+ else if (N.y < (1.0 - limit) * (N.x + N.z)) {
+ weight.x = N.x / (N.x + N.z);
weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
weight.z = 1.0 - weight.x;
}
else {
/* last case, we have a mix between three */
- weight.x = ((2.0 - limit) * nob.x + (limit - 1.0)) / (2.0 * limit - 1.0);
- weight.y = ((2.0 - limit) * nob.y + (limit - 1.0)) / (2.0 * limit - 1.0);
- weight.z = ((2.0 - limit) * nob.z + (limit - 1.0)) / (2.0 * limit - 1.0);
+ weight.x = ((2.0 - limit) * N.x + (limit - 1.0)) / (2.0 * limit - 1.0);
+ weight.y = ((2.0 - limit) * N.y + (limit - 1.0)) / (2.0 * limit - 1.0);
+ weight.z = ((2.0 - limit) * N.z + (limit - 1.0)) / (2.0 * limit - 1.0);
}
}
else {
@@ -2994,13 +3181,25 @@ void node_tex_image_box(vec3 texco,
}
color = vec4(0);
if (weight.x > 0.0) {
- color += weight.x * texture2D(ima, texco.yz);
+ vec2 uv = texco.yz;
+ if(signed_N.x < 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color += weight.x * texture2D(ima, uv);
}
if (weight.y > 0.0) {
- color += weight.y * texture2D(ima, texco.xz);
+ vec2 uv = texco.xz;
+ if(signed_N.y > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color += weight.y * texture2D(ima, uv);
}
if (weight.z > 0.0) {
- color += weight.z * texture2D(ima, texco.yx);
+ vec2 uv = texco.yx;
+ if(signed_N.z > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color += weight.z * texture2D(ima, uv);
}
alpha = color.a;
@@ -3536,6 +3735,8 @@ void node_light_path(
out float is_transmission_ray,
out float ray_length,
out float ray_depth,
+ out float diffuse_depth,
+ out float glossy_depth,
out float transparent_depth,
out float transmission_depth)
{
@@ -3548,6 +3749,8 @@ void node_light_path(
is_transmission_ray = 0.0;
ray_length = 1.0;
ray_depth = 1.0;
+ diffuse_depth = 1.0;
+ glossy_depth = 1.0;
transparent_depth = 1.0;
transmission_depth = 1.0;
}
@@ -3559,12 +3762,12 @@ void node_light_falloff(float strength, float tsmooth, out float quadratic, out
constant = strength;
}
-void node_object_info(out vec3 location, out float object_index, out float material_index, out float random)
+void node_object_info(mat4 obmat, vec3 info, out vec3 location, out float object_index, out float material_index, out float random)
{
- location = vec3(0.0);
- object_index = 0.0;
- material_index = 0.0;
- random = 0.0;
+ location = obmat[3].xyz;
+ object_index = info.x;
+ material_index = info.y;
+ random = info.z;
}
void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c
index 6ea311b2c7b..f837789914e 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.c
+++ b/source/blender/ikplugin/intern/iksolver_plugin.c
@@ -217,9 +217,27 @@ static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[3][3]) // nr =
copy_m4_m3(ikmat, ik_mat);
if (pchan->parent)
- mul_m4_series(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat);
+ mul_m4_m4m4(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat);
else
- mul_m4_m4m4(pchan->pose_mat, pchan->chan_mat, ikmat);
+ copy_m4_m4(pchan->pose_mat, pchan->chan_mat);
+
+#ifdef USE_NONUNIFORM_SCALE
+ /* apply IK mat, but as if the bones have uniform scale since the IK solver
+ * is not aware of non-uniform scale */
+ float scale[3];
+ mat4_to_size(scale, pchan->pose_mat);
+ normalize_v3_length(pchan->pose_mat[0], scale[1]);
+ normalize_v3_length(pchan->pose_mat[2], scale[1]);
+#endif
+
+ mul_m4_m4m4(pchan->pose_mat, pchan->pose_mat, ikmat);
+
+#ifdef USE_NONUNIFORM_SCALE
+ float ik_scale[3];
+ mat3_to_size(ik_scale, ik_mat);
+ normalize_v3_length(pchan->pose_mat[0], scale[0] * ik_scale[0]);
+ normalize_v3_length(pchan->pose_mat[2], scale[2] * ik_scale[2]);
+#endif
/* calculate head */
copy_v3_v3(pchan->pose_head, pchan->pose_mat[3]);
@@ -308,6 +326,10 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
/* change length based on bone size */
length = bone->length * len_v3(R_bonemat[1]);
+ /* basis must be pure rotation */
+ normalize_m3(R_bonemat);
+ normalize_m3(R_parmat);
+
/* compute rest basis and its inverse */
copy_m3_m3(rest_basis, bone->bone_mat);
transpose_m3_m3(irest_basis, bone->bone_mat);
@@ -317,11 +339,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
mul_m3_m3m3(full_basis, iR_parmat, R_bonemat);
mul_m3_m3m3(basis, irest_basis, full_basis);
- /* basis must be pure rotation */
- normalize_m3(basis);
-
/* transform offset into local bone space */
- normalize_m3(iR_parmat);
mul_m3_v3(iR_parmat, start);
IK_SetTransform(seg, start, rest_basis, basis, length);
@@ -545,18 +563,6 @@ void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan
tree->pchan[a]->flag |= POSE_CHAIN;
}
-#ifdef USE_NONUNIFORM_SCALE
- float (*pchan_scale_data)[3] = MEM_mallocN(sizeof(float[3]) * tree->totchannel, __func__);
-
- for (a = 0; a < tree->totchannel; a++) {
- mat4_to_size(pchan_scale_data[a], tree->pchan[a]->pose_mat);
-
- /* make uniform at y scale since this controls the length */
- normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][1]);
- normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][1]);
- }
-#endif
-
/* 5. execute the IK solver */
execute_posetree(scene, ob, tree);
@@ -571,14 +577,6 @@ void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan
where_is_ik_bone(tree->pchan[a], tree->basis_change[a]);
}
-#ifdef USE_NONUNIFORM_SCALE
- for (a = 0; a < tree->totchannel; a++) {
- normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][0]);
- normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][2]);
- }
- MEM_freeN(pchan_scale_data);
-#endif
-
/* 7. and free */
BLI_remlink(&pchan_root->iktree, tree);
free_posetree(tree);
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index b32f8c54cd6..c3950d8eb83 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -130,16 +130,6 @@ if(WITH_CODEC_AVI)
add_definitions(-DWITH_AVI)
endif()
-if(WITH_CODEC_QUICKTIME)
- list(APPEND INC
- ../quicktime
- )
- list(APPEND INC_SYS
- ${QUICKTIME_INCLUDE_DIRS}
- )
- add_definitions(-DWITH_QUICKTIME)
-endif()
-
if(WITH_CODEC_FFMPEG)
list(APPEND INC
../../../intern/ffmpeg
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 52febe642a0..ff1784c54dd 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -77,6 +77,16 @@ void IMB_colormanagement_transform(float *buffer, int width, int height, int cha
const char *from_colorspace, const char *to_colorspace, bool predivide);
void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels,
const char *from_colorspace, const char *to_colorspace, bool predivide);
+void IMB_colormanagement_transform_byte(unsigned char *buffer, int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace);
+void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer, int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace);
+void IMB_colormanagement_transform_from_byte(float *float_buffer, unsigned char *byte_buffer,
+ int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace);
+void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, unsigned char *byte_buffer,
+ int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace);
void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace);
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], struct ColorSpace *colorspace);
@@ -152,7 +162,7 @@ void IMB_colormanagment_colorspace_from_ibuf_ftype(struct ColorManagedColorspace
/* ** RNA helper functions ** */
void IMB_colormanagement_display_items_add(struct EnumPropertyItem **items, int *totitem);
void IMB_colormanagement_view_items_add(struct EnumPropertyItem **items, int *totitem, const char *display_name);
-void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem);
+void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem, const char *view_name);
void IMB_colormanagement_colorspace_items_add(struct EnumPropertyItem **items, int *totitem);
/* ** Tile-based buffer management ** */
@@ -185,6 +195,8 @@ void IMB_colormanagement_processor_apply_v3(struct ColormanageProcessor *cm_proc
void IMB_colormanagement_processor_apply_pixel(struct ColormanageProcessor *cm_processor, float *pixel, int channels);
void IMB_colormanagement_processor_apply(struct ColormanageProcessor *cm_processor, float *buffer, int width, int height,
int channels, bool predivide);
+void IMB_colormanagement_processor_apply_byte(struct ColormanageProcessor *cm_processor,
+ unsigned char *buffer, int width, int height, int channels);
void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor);
/* ** OpenGL drawing routines using GLSL for color space transform ** */
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 93d2b3e0cd0..f1f36351e79 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -166,7 +166,7 @@ struct ImBuf *IMB_makeSingleUser(struct ImBuf *ibuf);
*
* \attention Defined in allocimbuf.c
*/
-struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1);
+struct ImBuf *IMB_dupImBuf(const struct ImBuf *ibuf1);
/**
*
@@ -205,6 +205,7 @@ typedef enum IMB_BlendMode {
IMB_BLEND_SATURATION = 21,
IMB_BLEND_LUMINOSITY = 22,
IMB_BLEND_COLOR = 23,
+ IMB_BLEND_INTERPOLATE = 24,
IMB_BLEND_COPY = 1000,
IMB_BLEND_COPY_RGB = 1001,
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index f4b2539d7d7..ee51854d7ed 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -237,9 +237,8 @@ typedef struct ImBuf {
/**
* \name Imbuf Component flags
* \brief These flags determine the components of an ImBuf struct.
- */
-/**@{*/
-/** \brief Flag defining the components of the ImBuf struct. */
+ *
+ * \{ */
#define IB_rect (1 << 0)
#define IB_test (1 << 1)
@@ -259,15 +258,20 @@ typedef struct ImBuf {
#define IB_thumbnail (1 << 15)
#define IB_multiview (1 << 16)
+/** \} */
+
/**
* \name Imbuf preset profile tags
* \brief Some predefined color space profiles that 8 bit imbufs can represent
- */
+ *
+ * \{ */
#define IB_PROFILE_NONE 0
#define IB_PROFILE_LINEAR_RGB 1
#define IB_PROFILE_SRGB 2
#define IB_PROFILE_CUSTOM 3
+/** \} */
+
/* dds */
#ifdef WITH_DDS
#ifndef DDS_MAKEFOURCC
@@ -291,15 +295,22 @@ typedef struct ImBuf {
#endif /* DDS */
extern const char *imb_ext_image[];
-extern const char *imb_ext_image_qt[];
extern const char *imb_ext_movie[];
extern const char *imb_ext_audio[];
/* image formats that can only be loaded via filepath */
extern const char *imb_ext_image_filepath_only[];
+/**
+ * \name Imbuf Color Management Flag
+ * \brief Used with #ImBuf.colormanage_flag
+ *
+ * \{ */
+
enum {
IMB_COLORMANAGE_IS_DATA = (1 << 0)
};
-#endif
+/** \} */
+
+#endif /* __IMB_IMBUF_TYPES_H__ */
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index d89393b9903..b10ae4f6fe9 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -40,10 +40,7 @@
# include <mmsystem.h>
# include <memory.h>
# include <commdlg.h>
-
-# ifndef FREE_WINDOWS
-# include <vfw.h>
-# endif
+# include <vfw.h>
# undef AVIIF_KEYFRAME // redefined in AVI_avi.h
# undef AVIIF_LIST // redefined in AVI_avi.h
@@ -66,12 +63,6 @@
# include "AVI_avi.h"
#endif
-#ifdef WITH_QUICKTIME
-# if defined(_WIN32) || defined(__APPLE__)
-# include "quicktime_import.h"
-# endif /* _WIN32 || __APPLE__ */
-#endif /* WITH_QUICKTIME */
-
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -130,7 +121,7 @@ struct anim {
/* avi */
struct _AviMovie *avi;
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
/* windows avi */
int avistreams;
int firstvideo;
@@ -140,11 +131,6 @@ struct anim {
PGETFRAME pgf;
#endif
-#ifdef WITH_QUICKTIME
- /* quicktime */
- struct _QuicktimeMovie *qtime;
-#endif /* WITH_QUICKTIME */
-
#ifdef WITH_FFMPEG
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index b75f12b239d..0b4557e7bef 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -79,6 +79,8 @@ typedef struct ColorManagedLook {
struct ColorManagedLook *next, *prev;
int index;
char name[MAX_COLORSPACE_NAME];
+ char ui_name[MAX_COLORSPACE_NAME];
+ char view[MAX_COLORSPACE_NAME];
char process_space[MAX_COLORSPACE_NAME];
bool is_noop;
} ColorManagedLook;
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index ef3743d9c8a..6e9bfa1fc4e 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -89,11 +89,14 @@ void imb_mmap_unlock(void)
void imb_freemipmapImBuf(ImBuf *ibuf)
{
int a;
-
- for (a = 1; a < ibuf->miptot; a++) {
- if (ibuf->mipmap[a - 1])
- IMB_freeImBuf(ibuf->mipmap[a - 1]);
- ibuf->mipmap[a - 1] = NULL;
+
+ /* Do not trust ibuf->miptot, in some cases IMB_remakemipmap can leave unfreed unused levels,
+ * leading to memory leaks... */
+ for (a = 0; a < IMB_MIPMAP_LEVELS; a++) {
+ if (ibuf->mipmap[a] != NULL) {
+ IMB_freeImBuf(ibuf->mipmap[a]);
+ ibuf->mipmap[a] = NULL;
+ }
}
ibuf->miptot = 0;
@@ -503,7 +506,7 @@ bool IMB_initImBuf(struct ImBuf *ibuf,
}
/* does no zbuffers? */
-ImBuf *IMB_dupImBuf(ImBuf *ibuf1)
+ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
{
ImBuf *ibuf2, tbuf;
int flags = 0;
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index a40b257b75b..25b0c0d7b1a 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -37,10 +37,7 @@
#include <mmsystem.h>
#include <memory.h>
#include <commdlg.h>
-
-#ifndef FREE_WINDOWS
#include <vfw.h>
-#endif
#undef AVIIF_KEYFRAME /* redefined in AVI_avi.h */
#undef AVIIF_LIST /* redefined in AVI_avi.h */
@@ -76,12 +73,6 @@
# include "AVI_avi.h"
#endif
-#ifdef WITH_QUICKTIME
-#if defined(_WIN32) || defined(__APPLE__)
-#include "quicktime_import.h"
-#endif /* _WIN32 || __APPLE__ */
-#endif /* WITH_QUICKTIME */
-
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -173,7 +164,7 @@ static void an_stringenc(char *string, const char *head, const char *tail, unsig
#ifdef WITH_AVI
static void free_anim_avi(struct anim *anim)
{
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
int i;
#endif
@@ -184,7 +175,7 @@ static void free_anim_avi(struct anim *anim)
MEM_freeN(anim->avi);
anim->avi = NULL;
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
if (anim->pgf) {
AVIStreamGetFrameClose(anim->pgf);
@@ -224,9 +215,6 @@ void IMB_free_anim(struct anim *anim)
free_anim_avi(anim);
#endif
-#ifdef WITH_QUICKTIME
- free_anim_quicktime(anim);
-#endif
#ifdef WITH_FFMPEG
free_anim_ffmpeg(anim);
#endif
@@ -283,7 +271,7 @@ static int startavi(struct anim *anim)
{
AviError avierror;
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
HRESULT hr;
int i, firstvideo = -1;
int streamcount;
@@ -304,7 +292,7 @@ static int startavi(struct anim *anim)
avierror = AVI_open_movie(anim->name, anim->avi);
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
if (avierror == AVI_ERROR_COMPRESSION) {
AVIFileInit();
hr = AVIFileOpen(&anim->pfile, anim->name, OF_READ, 0L);
@@ -401,7 +389,7 @@ static ImBuf *avi_fetchibuf(struct anim *anim, int position)
return NULL;
}
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
if (anim->avistreams) {
LPBITMAPINFOHEADER lpbi;
@@ -516,6 +504,11 @@ static int startffmpeg(struct anim *anim)
avformat_close_input(&pFormatCtx);
return -1;
}
+ if (pCodecCtx->pix_fmt == AV_PIX_FMT_NONE) {
+ avcodec_close(anim->pCodecCtx);
+ avformat_close_input(&pFormatCtx);
+ return -1;
+ }
frame_rate = av_get_r_frame_rate_compat(pFormatCtx->streams[videoStream]);
if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
@@ -1217,9 +1210,6 @@ static ImBuf *anim_getnew(struct anim *anim)
free_anim_avi(anim);
#endif
-#ifdef WITH_QUICKTIME
- free_anim_quicktime(anim);
-#endif
#ifdef WITH_FFMPEG
free_anim_ffmpeg(anim);
#endif
@@ -1248,12 +1238,6 @@ static ImBuf *anim_getnew(struct anim *anim)
ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0);
break;
#endif
-#ifdef WITH_QUICKTIME
- case ANIM_QTIME:
- if (startquicktime(anim)) return (0);
- ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0);
- break;
-#endif
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
if (startffmpeg(anim)) return (0);
@@ -1343,21 +1327,6 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim, int position,
anim->curposition = position;
break;
#endif
-#ifdef WITH_QUICKTIME
- case ANIM_QTIME:
- ibuf = qtime_fetchibuf(anim, position);
- if (ibuf) {
- if (ibuf->rect) {
- /* OCIO_TODO: should happen in quicktime module, but it currently doesn't have access
- * to color management's internals
- */
- ibuf->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace);
- }
-
- anim->curposition = position;
- }
- break;
-#endif
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
ibuf = ffmpeg_fetchibuf(anim, position, tc);
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
index 8b4e95ac452..429a19936a5 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.c
+++ b/source/blender/imbuf/intern/cineon/dpxlib.c
@@ -183,7 +183,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
if (verbose) printf("DPX: File is LSB.\n");
}
else {
- if (verbose) {
+ if (verbose) {
printf("DPX: Bad magic number %u in \"%s\".\n",
header.fileHeader.magic_num, byteStuff);
}
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c
index 6fb1bccf491..600642f5e44 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.c
+++ b/source/blender/imbuf/intern/cineon/logImageCore.c
@@ -177,19 +177,18 @@ unsigned int getRowLength(int width, LogImageElement logElement)
return ((width * logElement.depth * 10 - 1) / 32 + 1) * 4;
else if (logElement.packing == 1 || logElement.packing == 2)
return ((width * logElement.depth - 1) / 3 + 1) * 4;
-
+ break;
case 12:
if (logElement.packing == 0)
return ((width * logElement.depth * 12 - 1) / 32 + 1) * 4;
else if (logElement.packing == 1 || logElement.packing == 2)
return width * logElement.depth * 2;
-
+ break;
case 16:
return width * logElement.depth * 2;
- default:
- return 0;
}
+ return 0;
}
@@ -572,20 +571,20 @@ static int logImageElementGetData(LogImageFile *logImage, LogImageElement logEle
return logImageElementGetData10Packed(logImage, logElement, data);
else if (logElement.packing == 1 || logElement.packing == 2)
return logImageElementGetData10(logImage, logElement, data);
+ break;
case 12:
if (logElement.packing == 0)
return logImageElementGetData12Packed(logImage, logElement, data);
else if (logElement.packing == 1 || logElement.packing == 2)
return logImageElementGetData12(logImage, logElement, data);
+ break;
case 16:
return logImageElementGetData16(logImage, logElement, data);
-
- default:
- /* format not supported */
- return 1;
}
+ /* format not supported */
+ return 1;
}
static int logImageElementGetData1(LogImageFile *logImage, LogImageElement logElement, float *data)
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 01348549bc4..863bce125c5 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -47,6 +47,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_filetype.h"
+#include "IMB_filter.h"
#include "IMB_moviecache.h"
#include "MEM_guardedalloc.h"
@@ -63,6 +64,7 @@
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_sequencer.h"
#include "RNA_define.h"
@@ -214,7 +216,7 @@ typedef struct ColormanageCacheKey {
int display; /* display device name */
} ColormanageCacheKey;
-typedef struct ColormnaageCacheData {
+typedef struct ColormanageCacheData {
int flag; /* view flags of cached buffer */
int look; /* Additional artistics transform */
float exposure; /* exposure value cached buffer is calculated with */
@@ -222,12 +224,12 @@ typedef struct ColormnaageCacheData {
float dither; /* dither value cached buffer is calculated with */
CurveMapping *curve_mapping; /* curve mapping used for cached buffer */
int curve_mapping_timestamp; /* time stamp of curve mapping used for cached buffer */
-} ColormnaageCacheData;
+} ColormanageCacheData;
typedef struct ColormanageCache {
struct MovieCache *moviecache;
- ColormnaageCacheData *data;
+ ColormanageCacheData *data;
} ColormanageCache;
static struct MovieCache *colormanage_moviecache_get(const ImBuf *ibuf)
@@ -238,7 +240,7 @@ static struct MovieCache *colormanage_moviecache_get(const ImBuf *ibuf)
return ibuf->colormanage_cache->moviecache;
}
-static ColormnaageCacheData *colormanage_cachedata_get(const ImBuf *ibuf)
+static ColormanageCacheData *colormanage_cachedata_get(const ImBuf *ibuf)
{
if (!ibuf->colormanage_cache)
return NULL;
@@ -281,7 +283,7 @@ static struct MovieCache *colormanage_moviecache_ensure(ImBuf *ibuf)
return ibuf->colormanage_cache->moviecache;
}
-static void colormanage_cachedata_set(ImBuf *ibuf, ColormnaageCacheData *data)
+static void colormanage_cachedata_set(ImBuf *ibuf, ColormanageCacheData *data)
{
if (!ibuf->colormanage_cache)
ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
@@ -361,7 +363,7 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV
cache_ibuf = colormanage_cache_get_ibuf(ibuf, &key, cache_handle);
if (cache_ibuf) {
- ColormnaageCacheData *cache_data;
+ ColormanageCacheData *cache_data;
BLI_assert(cache_ibuf->x == ibuf->x &&
cache_ibuf->y == ibuf->y);
@@ -402,7 +404,7 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting
{
ColormanageCacheKey key;
ImBuf *cache_ibuf;
- ColormnaageCacheData *cache_data;
+ ColormanageCacheData *cache_data;
int view_flag = 1 << (view_settings->view - 1);
struct MovieCache *moviecache = colormanage_moviecache_ensure(ibuf);
CurveMapping *curve_mapping = view_settings->curve_mapping;
@@ -421,7 +423,7 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting
cache_ibuf->flags |= IB_rect;
/* store data which is needed to check whether cached buffer could be used for color managed display settings */
- cache_data = MEM_callocN(sizeof(ColormnaageCacheData), "color manage cache imbuf data");
+ cache_data = MEM_callocN(sizeof(ColormanageCacheData), "color manage cache imbuf data");
cache_data->look = view_settings->look;
cache_data->exposure = view_settings->exposure;
cache_data->gamma = view_settings->gamma;
@@ -710,7 +712,7 @@ void colormanage_cache_free(ImBuf *ibuf)
}
if (ibuf->colormanage_cache) {
- ColormnaageCacheData *cache_data = colormanage_cachedata_get(ibuf);
+ ColormanageCacheData *cache_data = colormanage_cachedata_get(ibuf);
struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
if (cache_data) {
@@ -1112,6 +1114,7 @@ void IMB_colormanagement_check_file_config(Main *bmain)
for (scene = bmain->scene.first; scene; scene = scene->id.next) {
ColorManagedColorspaceSettings *sequencer_colorspace_settings;
+ /* check scene color management settings */
colormanage_check_display_settings(&scene->display_settings, "scene", default_display);
colormanage_check_view_settings(&scene->display_settings, &scene->view_settings, "scene");
@@ -1122,6 +1125,15 @@ void IMB_colormanagement_check_file_config(Main *bmain)
if (sequencer_colorspace_settings->name[0] == '\0') {
BLI_strncpy(sequencer_colorspace_settings->name, global_role_default_sequencer, MAX_COLORSPACE_NAME);
}
+
+ /* check sequencer strip input color space settings */
+ Sequence *seq;
+ SEQ_BEGIN (scene->ed, seq) {
+ if (seq->strip) {
+ colormanage_check_colorspace_settings(&seq->strip->colorspace_settings, "sequencer strip");
+ }
+ }
+ SEQ_END
}
/* ** check input color space settings ** */
@@ -1227,7 +1239,12 @@ const char *IMB_colormanagement_get_float_colorspace(ImBuf *ibuf)
const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
{
- return ibuf->rect_colorspace->name;
+ if (ibuf->rect_colorspace) {
+ return ibuf->rect_colorspace->name;
+ }
+ else {
+ return IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
+ }
}
/*********************** Threaded display buffer transform routines *************************/
@@ -1401,7 +1418,7 @@ static void *do_display_buffer_apply_thread(void *handle_v)
bool is_data = handle->is_data;
if (cm_processor == NULL) {
- if (display_buffer_byte) {
+ if (display_buffer_byte && display_buffer_byte != handle->byte_buffer) {
IMB_buffer_byte_from_byte(display_buffer_byte, handle->byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
false, width, height, width, width);
}
@@ -1505,6 +1522,10 @@ static bool is_ibuf_rect_in_display_space(ImBuf *ibuf, const ColorManagedViewSet
{
const char *from_colorspace = ibuf->rect_colorspace->name;
const char *to_colorspace = IMB_colormanagement_get_display_colorspace_name(view_settings, display_settings);
+ ColorManagedLook *look_descr = colormanage_look_get_named(view_settings->look);
+ if (look_descr != NULL && !STREQ(look_descr->process_space, "")) {
+ return false;
+ }
if (to_colorspace && STREQ(from_colorspace, to_colorspace))
return true;
@@ -1550,21 +1571,25 @@ static void colormanage_display_buffer_process(ImBuf *ibuf, unsigned char *displ
typedef struct ProcessorTransformThread {
ColormanageProcessor *cm_processor;
- float *buffer;
+ unsigned char *byte_buffer;
+ float *float_buffer;
int width;
int start_line;
int tot_line;
int channels;
bool predivide;
+ bool float_from_byte;
} ProcessorTransformThread;
typedef struct ProcessorTransformInit {
ColormanageProcessor *cm_processor;
- float *buffer;
+ unsigned char *byte_buffer;
+ float *float_buffer;
int width;
int height;
int channels;
bool predivide;
+ bool float_from_byte;
} ProcessorTransformInitData;
static void processor_transform_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
@@ -1572,17 +1597,24 @@ static void processor_transform_init_handle(void *handle_v, int start_line, int
ProcessorTransformThread *handle = (ProcessorTransformThread *) handle_v;
ProcessorTransformInitData *init_data = (ProcessorTransformInitData *) init_data_v;
- int channels = init_data->channels;
- int width = init_data->width;
- bool predivide = init_data->predivide;
+ const int channels = init_data->channels;
+ const int width = init_data->width;
+ const bool predivide = init_data->predivide;
+ const bool float_from_byte = init_data->float_from_byte;
- size_t offset = ((size_t)channels) * start_line * width;
+ const size_t offset = ((size_t)channels) * start_line * width;
memset(handle, 0, sizeof(ProcessorTransformThread));
handle->cm_processor = init_data->cm_processor;
- handle->buffer = init_data->buffer + offset;
+ if (init_data->byte_buffer != NULL) {
+ /* TODO(serge): Offset might be different for byte and float buffers. */
+ handle->byte_buffer = init_data->byte_buffer + offset;
+ }
+ if (init_data->float_buffer != NULL) {
+ handle->float_buffer = init_data->float_buffer + offset;
+ }
handle->width = width;
@@ -1591,33 +1623,63 @@ static void processor_transform_init_handle(void *handle_v, int start_line, int
handle->channels = channels;
handle->predivide = predivide;
+ handle->float_from_byte = float_from_byte;
}
static void *do_processor_transform_thread(void *handle_v)
{
ProcessorTransformThread *handle = (ProcessorTransformThread *) handle_v;
- float *buffer = handle->buffer;
- int channels = handle->channels;
- int width = handle->width;
- int height = handle->tot_line;
- bool predivide = handle->predivide;
-
- IMB_colormanagement_processor_apply(handle->cm_processor, buffer, width, height, channels, predivide);
+ unsigned char *byte_buffer = handle->byte_buffer;
+ float *float_buffer = handle->float_buffer;
+ const int channels = handle->channels;
+ const int width = handle->width;
+ const int height = handle->tot_line;
+ const bool predivide = handle->predivide;
+ const bool float_from_byte = handle->float_from_byte;
+
+ if (float_from_byte) {
+ IMB_buffer_float_from_byte(float_buffer, byte_buffer,
+ IB_PROFILE_SRGB, IB_PROFILE_SRGB,
+ false,
+ width, height, width, width);
+ IMB_colormanagement_processor_apply(handle->cm_processor,
+ float_buffer,
+ width, height, channels,
+ predivide);
+ IMB_premultiply_rect_float(float_buffer, 4, width, height);
+ }
+ else {
+ if (byte_buffer != NULL) {
+ IMB_colormanagement_processor_apply_byte(handle->cm_processor,
+ byte_buffer,
+ width, height, channels);
+ }
+ if (float_buffer != NULL) {
+ IMB_colormanagement_processor_apply(handle->cm_processor,
+ float_buffer,
+ width, height, channels,
+ predivide);
+ }
+ }
return NULL;
}
-static void processor_transform_apply_threaded(float *buffer, int width, int height, int channels,
- ColormanageProcessor *cm_processor, bool predivide)
+static void processor_transform_apply_threaded(unsigned char *byte_buffer, float *float_buffer,
+ const int width, const int height, const int channels,
+ ColormanageProcessor *cm_processor,
+ const bool predivide, const bool float_from_byte)
{
ProcessorTransformInitData init_data;
init_data.cm_processor = cm_processor;
- init_data.buffer = buffer;
+ init_data.byte_buffer = byte_buffer;
+ init_data.float_buffer = float_buffer;
init_data.width = width;
init_data.height = height;
init_data.channels = channels;
init_data.predivide = predivide;
+ init_data.float_from_byte = float_from_byte;
IMB_processor_apply_threaded(height, sizeof(ProcessorTransformThread), &init_data,
processor_transform_init_handle, do_processor_transform_thread);
@@ -1626,8 +1688,10 @@ static void processor_transform_apply_threaded(float *buffer, int width, int hei
/*********************** Color space transformation functions *************************/
/* convert the whole buffer from specified by name color space to another - internal implementation */
-static void colormanagement_transform_ex(float *buffer, int width, int height, int channels, const char *from_colorspace,
- const char *to_colorspace, bool predivide, bool do_threaded)
+static void colormanagement_transform_ex(unsigned char *byte_buffer, float *float_buffer,
+ int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace,
+ bool predivide, bool do_threaded)
{
ColormanageProcessor *cm_processor;
@@ -1644,10 +1708,19 @@ static void colormanagement_transform_ex(float *buffer, int width, int height, i
cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
- if (do_threaded)
- processor_transform_apply_threaded(buffer, width, height, channels, cm_processor, predivide);
- else
- IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
+ if (do_threaded) {
+ processor_transform_apply_threaded(byte_buffer, float_buffer,
+ width, height, channels,
+ cm_processor, predivide, false);
+ }
+ else {
+ if (byte_buffer != NULL) {
+ IMB_colormanagement_processor_apply_byte(cm_processor, byte_buffer, width, height, channels);
+ }
+ if (float_buffer != NULL) {
+ IMB_colormanagement_processor_apply(cm_processor, float_buffer, width, height, channels, predivide);
+ }
+ }
IMB_colormanagement_processor_free(cm_processor);
}
@@ -1656,7 +1729,7 @@ static void colormanagement_transform_ex(float *buffer, int width, int height, i
void IMB_colormanagement_transform(float *buffer, int width, int height, int channels,
const char *from_colorspace, const char *to_colorspace, bool predivide)
{
- colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
+ colormanagement_transform_ex(NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
}
/* convert the whole buffer from specified by name color space to another
@@ -1665,7 +1738,60 @@ void IMB_colormanagement_transform(float *buffer, int width, int height, int cha
void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels,
const char *from_colorspace, const char *to_colorspace, bool predivide)
{
- colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
+ colormanagement_transform_ex(NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
+}
+
+/* Similar to functions above, but operates on byte buffer. */
+void IMB_colormanagement_transform_byte(unsigned char *buffer, int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace)
+{
+ colormanagement_transform_ex(buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, false);
+}
+void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer, int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace)
+{
+ colormanagement_transform_ex(buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, true);
+}
+
+/* Similar to above, but gets float buffer from display one. */
+void IMB_colormanagement_transform_from_byte(float *float_buffer, unsigned char *byte_buffer,
+ int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace)
+{
+ IMB_buffer_float_from_byte(float_buffer, byte_buffer,
+ IB_PROFILE_SRGB, IB_PROFILE_SRGB,
+ true,
+ width, height, width, width);
+ IMB_colormanagement_transform(float_buffer,
+ width, height, channels,
+ from_colorspace, to_colorspace,
+ true);
+}
+void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, unsigned char *byte_buffer,
+ int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace)
+{
+ ColormanageProcessor *cm_processor;
+ if (from_colorspace == NULL || from_colorspace[0] == '\0') {
+ return;
+ }
+ if (STREQ(from_colorspace, to_colorspace)) {
+ /* Because this function always takes a byte buffer and returns a float buffer, it must
+ * always do byte-to-float conversion of some kind. To avoid threading overhead
+ * IMB_buffer_float_from_byte is used when color spaces are identical. See T51002.
+ */
+ IMB_buffer_float_from_byte(float_buffer, byte_buffer,
+ IB_PROFILE_SRGB, IB_PROFILE_SRGB,
+ false,
+ width, height, width, width);
+ IMB_premultiply_rect_float(float_buffer, 4, width, height);
+ return;
+ }
+ cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
+ processor_transform_apply_threaded(byte_buffer, float_buffer,
+ width, height, channels,
+ cm_processor, false, true);
+ IMB_colormanagement_processor_free(cm_processor);
}
void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace)
@@ -1957,6 +2083,10 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, boo
}
}
+ if (colormanaged_ibuf != ibuf) {
+ IMB_metadata_copy(colormanaged_ibuf, ibuf);
+ }
+
return colormanaged_ibuf;
}
@@ -1969,12 +2099,14 @@ void IMB_colormanagement_buffer_make_display_space(float *buffer, unsigned char
size_t float_buffer_size = ((size_t)width) * height * channels * sizeof(float);
float *display_buffer_float = MEM_mallocN(float_buffer_size, "byte_buffer_make_display_space");
+ /* TODO(sergey): Convert float directly to byte buffer. */
+
memcpy(display_buffer_float, buffer, float_buffer_size);
cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
- processor_transform_apply_threaded(display_buffer_float, width, height, channels,
- cm_processor, true);
+ processor_transform_apply_threaded(NULL, display_buffer_float, width, height, channels,
+ cm_processor, true, false);
IMB_buffer_byte_from_float(display_buffer, display_buffer_float,
channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
@@ -2440,6 +2572,14 @@ const char *IMB_colormanagement_colorspace_get_indexed_name(int index)
void IMB_colormanagment_colorspace_from_ibuf_ftype(ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
{
+ /* Don't modify non-color data space, it does not change with file type. */
+ ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
+
+ if (colorspace && colorspace->is_data) {
+ return;
+ }
+
+ /* Get color space from file type. */
const ImFileType *type;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
@@ -2463,9 +2603,17 @@ ColorManagedLook *colormanage_look_add(const char *name, const char *process_spa
look = MEM_callocN(sizeof(ColorManagedLook), "ColorManagedLook");
look->index = index + 1;
BLI_strncpy(look->name, name, sizeof(look->name));
+ BLI_strncpy(look->ui_name, name, sizeof(look->ui_name));
BLI_strncpy(look->process_space, process_space, sizeof(look->process_space));
look->is_noop = is_noop;
+ /* Detect view specific looks. */
+ const char *separator_offset = strstr(look->name, " - ");
+ if (separator_offset) {
+ BLI_strncpy(look->view, look->name, separator_offset - look->name + 1);
+ BLI_strncpy(look->ui_name, separator_offset + strlen(" - "), sizeof(look->ui_name));
+ }
+
BLI_addtail(&global_looks, look);
global_tot_looks++;
@@ -2566,15 +2714,27 @@ void IMB_colormanagement_view_items_add(EnumPropertyItem **items, int *totitem,
}
}
-void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem)
+void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem, const char *view_name)
{
ColorManagedLook *look;
+ const char *view_filter = NULL;
+
+ /* Test if this view transform is limited to specific looks. */
+ for (look = global_looks.first; look; look = look->next) {
+ if (STREQ(look->view, view_name)) {
+ view_filter = view_name;
+ }
+ }
for (look = global_looks.first; look; look = look->next) {
+ if (!look->is_noop && view_filter && !STREQ(look->view, view_filter)) {
+ continue;
+ }
+
EnumPropertyItem item;
item.value = look->index;
- item.name = look->name;
+ item.name = look->ui_name;
item.identifier = look->name;
item.icon = 0;
item.description = "";
@@ -3095,6 +3255,25 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo
}
}
+void IMB_colormanagement_processor_apply_byte(ColormanageProcessor *cm_processor,
+ unsigned char *buffer,
+ int width, int height, int channels)
+{
+ /* TODO(sergey): Would be nice to support arbitrary channels configurations,
+ * but for now it's not so important.
+ */
+ BLI_assert(channels == 4);
+ float pixel[4];
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ size_t offset = channels * (((size_t)y) * width + x);
+ rgba_uchar_to_float(pixel, buffer + offset);
+ IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
+ rgba_float_to_uchar(buffer + offset, pixel);
+ }
+ }
+}
+
void IMB_colormanagement_processor_free(ColormanageProcessor *cm_processor)
{
if (cm_processor->curve_mapping)
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index 12e03f55450..67a0b0ffd00 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -37,7 +37,7 @@ extern "C" {
#include <stdio.h> // printf
#include <fstream>
-#if defined (WIN32) && !defined(FREE_WINDOWS)
+#if defined (WIN32)
#include "utfconv.h"
#endif
@@ -62,7 +62,7 @@ int imb_save_dds(struct ImBuf *ibuf, const char *name, int /*flags*/)
/* open file for writing */
std::ofstream fildes;
-#if defined (WIN32) && !defined(FREE_WINDOWS)
+#if defined (WIN32)
wchar_t *wname = alloc_utf16_from_8(name, 0);
fildes.open(wname);
free(wname);
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index 3d3e8a0646a..7ed5c8ffbcb 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -47,10 +47,6 @@
#include "dds/dds_api.h"
#endif
-#ifdef WITH_QUICKTIME
-#include "quicktime_import.h"
-#endif
-
static int imb_ftype_default(const ImFileType *type, ImBuf *ibuf)
{
return (ibuf->ftype == type->filetype);
@@ -101,10 +97,6 @@ void imb_filetypes_init(void)
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++)
if (type->init)
type->init();
-
-#ifdef WITH_QUICKTIME
- quicktime_init();
-#endif
}
void imb_filetypes_exit(void)
@@ -114,9 +106,5 @@ void imb_filetypes_exit(void)
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++)
if (type->exit)
type->exit();
-
-#ifdef WITH_QUICKTIME
- quicktime_exit();
-#endif
}
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 1987c6d2a9a..38609d0a342 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -406,7 +406,7 @@ void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
const int height = ibuf->y;
const int depth = 4; /* always 4 channels */
const int chsize = ibuf->rect_float ? sizeof(float) : sizeof(unsigned char);
- const int bsize = width * height * depth * chsize;
+ const size_t bsize = ((size_t)width) * height * depth * chsize;
const bool is_float = (ibuf->rect_float != NULL);
void *dstbuf = (void *) MEM_dupallocN(ibuf->rect_float ? (void *) ibuf->rect_float : (void *) ibuf->rect);
char *dstmask = mask == NULL ? NULL : (char *) MEM_dupallocN(mask);
@@ -499,7 +499,9 @@ void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
/* keep the original buffer up to date. */
memcpy(srcbuf, dstbuf, bsize);
- if (dstmask != NULL) memcpy(srcmask, dstmask, width * height);
+ if (dstmask != NULL) {
+ memcpy(srcmask, dstmask, ((size_t)width) * height);
+ }
}
/* free memory */
diff --git a/source/blender/imbuf/intern/imbuf.h b/source/blender/imbuf/intern/imbuf.h
index 897a149a45c..90dad70fa61 100644
--- a/source/blender/imbuf/intern/imbuf.h
+++ b/source/blender/imbuf/intern/imbuf.h
@@ -67,8 +67,6 @@
# define BIG_LONG SWAP_LONG
#endif
-typedef unsigned char uchar;
-
#define IMB_DPI_DEFAULT 72.0f
#endif /* __IMBUF_H__ */
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index 7a9fa2b9768..6c0849358a5 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -48,36 +48,24 @@
#define IMAGIC 0732
typedef struct {
- unsigned short imagic; /* stuff saved on disk . . */
- unsigned short type;
- unsigned short dim;
- unsigned short xsize;
- unsigned short ysize;
- unsigned short zsize;
- unsigned int min;
- unsigned int max;
- unsigned int wastebytes;
- char name[80];
- unsigned int colormap;
-
- int file; /* stuff used in core only */
- unsigned short flags;
- short dorev;
- short x;
- short y;
- short z;
- short cnt;
- unsigned short *ptr;
- unsigned short *base;
- unsigned short *tmpbuf;
- unsigned int offset;
- unsigned int rleend; /* for rle images */
- unsigned int *rowstart; /* for rle images */
- const int *rowsize; /* for rle images */
+ ushort imagic; /* stuff saved on disk . . */
+ ushort type;
+ ushort dim;
+ ushort xsize;
+ ushort ysize;
+ ushort zsize;
+ uint min;
+ uint max;
+ uchar _pad1[4];
+ char name[80];
+ uint colormap;
+ uchar _pad2[404];
} IMAGE;
#define HEADER_SIZE 512
+BLI_STATIC_ASSERT(sizeof(IMAGE) == HEADER_SIZE, "Invalid header size");
+
#define RINTLUM (79)
#define GINTLUM (156)
#define BINTLUM (21)
@@ -106,68 +94,72 @@ typedef struct {
/* local struct for mem access */
typedef struct MFileOffset {
const uchar *_file_data;
- unsigned int _file_offset;
+ uint _file_offset;
} MFileOffset;
-#define MFILE_DATA(inf) ((void)0, (inf)->_file_data + (inf)->_file_offset)
+#define MFILE_DATA(inf) ((void)0, ((inf)->_file_data + (inf)->_file_offset))
#define MFILE_STEP(inf, step) { (inf)->_file_offset += step; } ((void)0)
#define MFILE_SEEK(inf, pos) { (inf)->_file_offset = pos; } ((void)0)
+/* error flags */
+#define DIRTY_FLAG_EOF (1 << 0)
+#define DIRTY_FLAG_ENCODING (1 << 1)
+
/* funcs */
static void readheader(MFileOffset *inf, IMAGE *image);
static int writeheader(FILE *outf, IMAGE *image);
-static unsigned short getshort(MFileOffset *inf);
-static unsigned int getlong(MFileOffset *inf);
-static void putshort(FILE *outf, unsigned short val);
-static int putlong(FILE *outf, unsigned int val);
-static int writetab(FILE *outf, unsigned int *tab, int len);
-static void readtab(MFileOffset *inf, unsigned int *tab, int len);
+static ushort getshort(MFileOffset *inf);
+static uint getlong(MFileOffset *inf);
+static void putshort(FILE *outf, ushort val);
+static int putlong(FILE *outf, uint val);
+static int writetab(FILE *outf, uint *tab, int len);
+static void readtab(MFileOffset *inf, uint *tab, int len);
-static void expandrow(unsigned char *optr, const unsigned char *iptr, int z);
-static void expandrow2(float *optr, const unsigned char *iptr, int z);
-static void interleaverow(unsigned char *lptr, const unsigned char *cptr, int z, int n);
-static void interleaverow2(float *lptr, const unsigned char *cptr, int z, int n);
-static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt);
-static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n);
+static int expandrow(uchar *optr, const uchar *optr_end, const uchar *iptr, const uchar *iptr_end, int z);
+static int expandrow2(float *optr, const float *optr_end, const uchar *iptr, const uchar *iptr_end, int z);
+static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n);
+static void interleaverow2(float *lptr, const uchar *cptr, int z, int n);
+static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int cnt);
+static void lumrow(uchar *rgbptr, uchar *lumptr, int n);
/*
* byte order independent read/write of shorts and ints.
*
*/
-static unsigned short getshort(MFileOffset *inf)
+static ushort getshort(MFileOffset *inf)
{
- const unsigned char *buf;
+ const uchar *buf;
buf = MFILE_DATA(inf);
MFILE_STEP(inf, 2);
-
- return (buf[0] << 8) + (buf[1] << 0);
+
+ return ((ushort)buf[0] << 8) + ((ushort)buf[1] << 0);
}
-static unsigned int getlong(MFileOffset *mofs)
+static uint getlong(MFileOffset *mofs)
{
- const unsigned char *buf;
+ const uchar *buf;
buf = MFILE_DATA(mofs);
MFILE_STEP(mofs, 4);
-
- return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0);
+
+ return ((uint)buf[0] << 24) + ((uint)buf[1] << 16) + ((uint)buf[2] << 8) + ((uint)buf[3] << 0);
}
-static void putshort(FILE *outf, unsigned short val)
+static void putshort(FILE *outf, ushort val)
{
- unsigned char buf[2];
+ uchar buf[2];
buf[0] = (val >> 8);
buf[1] = (val >> 0);
fwrite(buf, 2, 1, outf);
}
-static int putlong(FILE *outf, unsigned int val)
+static int putlong(FILE *outf, uint val)
{
- unsigned char buf[4];
+ uchar buf[4];
buf[0] = (val >> 24);
buf[1] = (val >> 16);
@@ -205,7 +197,7 @@ static int writeheader(FILE *outf, IMAGE *image)
return fwrite("no name", 8, 1, outf);
}
-static int writetab(FILE *outf, unsigned int *tab, int len)
+static int writetab(FILE *outf, uint *tab, int len)
{
int r = 0;
@@ -216,7 +208,7 @@ static int writetab(FILE *outf, unsigned int *tab, int len)
return r;
}
-static void readtab(MFileOffset *inf, unsigned int *tab, int len)
+static void readtab(MFileOffset *inf, uint *tab, int len)
{
while (len) {
*tab++ = getlong(inf);
@@ -242,12 +234,12 @@ static void test_endian_zbuf(struct ImBuf *ibuf)
}
/* from misc_util: flip the bytes from x */
-#define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1])
+#define GS(x) (((uchar *)(x))[0] << 8 | ((uchar *)(x))[1])
/* this one is only def-ed once, strangely... */
#define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0])
-int imb_is_a_iris(const unsigned char *mem)
+int imb_is_a_iris(const uchar *mem)
{
return ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC));
}
@@ -259,46 +251,52 @@ int imb_is_a_iris(const unsigned char *mem)
*
*/
-struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
+struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
- unsigned int *base, *lptr = NULL;
+ uint *base, *lptr = NULL;
float *fbase, *fptr = NULL;
- unsigned int *zbase, *zptr;
- const unsigned char *rledat;
- unsigned int *starttab, *lengthtab;
+ uint *zbase, *zptr;
+ const uchar *rledat;
+ const uchar *mem_end = mem + size;
MFileOffset _inf_data = {mem, 0}, *inf = &_inf_data;
IMAGE image;
int x, y, z, tablen;
- int xsize, ysize, zsize;
int bpp, rle, cur, badorder;
ImBuf *ibuf;
+ uchar dirty_flag = 0;
- (void)size; /* unused */
-
- if (!imb_is_a_iris(mem)) return NULL;
+ if (size < HEADER_SIZE) {
+ return NULL;
+ }
+
+ if (!imb_is_a_iris(mem)) {
+ return NULL;
+ }
/* OCIO_TODO: only tested with 1 byte per pixel, not sure how to test with other settings */
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
- /*printf("new iris\n");*/
-
readheader(inf, &image);
if (image.imagic != IMAGIC) {
fprintf(stderr, "longimagedata: bad magic number in image file\n");
return(NULL);
}
-
+
rle = ISRLE(image.type);
bpp = BPP(image.type);
if (bpp != 1 && bpp != 2) {
fprintf(stderr, "longimagedata: image must have 1 or 2 byte per pix chan\n");
return(NULL);
}
-
- xsize = image.xsize;
- ysize = image.ysize;
- zsize = image.zsize;
-
+ if ((uint)image.zsize > 8) {
+ fprintf(stderr, "longimagedata: channels over 8 not supported\n");
+ return(NULL);
+ }
+
+ const int xsize = image.xsize;
+ const int ysize = image.ysize;
+ const int zsize = image.zsize;
+
if (flags & IB_test) {
ibuf = IMB_allocImBuf(image.xsize, image.ysize, 8 * image.zsize, 0);
if (ibuf) ibuf->ftype = IMB_FTYPE_IMAGIC;
@@ -306,12 +304,17 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha
}
if (rle) {
-
tablen = ysize * zsize * sizeof(int);
- starttab = (unsigned int *)MEM_mallocN(tablen, "iris starttab");
- lengthtab = (unsigned int *)MEM_mallocN(tablen, "iris endtab");
MFILE_SEEK(inf, HEADER_SIZE);
-
+
+ uint *starttab = MEM_mallocN(tablen, "iris starttab");
+ uint *lengthtab = MEM_mallocN(tablen, "iris endtab");
+
+#define MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(p) \
+ if (UNLIKELY((p) > mem_end)) { dirty_flag |= DIRTY_FLAG_EOF; goto fail_rle; } ((void)0)
+
+ MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(MFILE_DATA(inf) + ((4 * 2) * tablen));
+
readtab(inf, starttab, tablen);
readtab(inf, lengthtab, tablen);
@@ -335,7 +338,7 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha
ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect);
if (ibuf->planes > 32) ibuf->planes = 32;
base = ibuf->rect;
- zbase = (unsigned int *)ibuf->zbuf;
+ zbase = (uint *)ibuf->zbuf;
if (badorder) {
for (z = 0; z < zsize; z++) {
@@ -344,9 +347,11 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha
MFILE_SEEK(inf, starttab[y + z * ysize]);
rledat = MFILE_DATA(inf);
MFILE_STEP(inf, lengthtab[y + z * ysize]);
-
- expandrow((uchar *)lptr, rledat, 3 - z);
- lptr += xsize;
+ const uchar *rledat_next = MFILE_DATA(inf);
+ uint *lptr_next = lptr + xsize;
+ MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next);
+ dirty_flag |= expandrow((uchar *)lptr, (uchar *)lptr_next, rledat, rledat_next, 3 - z);
+ lptr = lptr_next;
}
}
}
@@ -354,17 +359,25 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha
lptr = base;
zptr = zbase;
for (y = 0; y < ysize; y++) {
-
+
+ uint *lptr_next = lptr + xsize;
+ uint *zptr_next = zptr + xsize;
+
for (z = 0; z < zsize; z++) {
MFILE_SEEK(inf, starttab[y + z * ysize]);
rledat = MFILE_DATA(inf);
MFILE_STEP(inf, lengthtab[y + z * ysize]);
-
- if (z < 4) expandrow((uchar *)lptr, rledat, 3 - z);
- else if (z < 8) expandrow((uchar *)zptr, rledat, 7 - z);
+ const uchar *rledat_next = MFILE_DATA(inf);
+ MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next);
+ if (z < 4) {
+ dirty_flag |= expandrow((uchar *)lptr, (uchar *)lptr_next, rledat, rledat_next, 3 - z);
+ }
+ else if (z < 8) {
+ dirty_flag |= expandrow((uchar *)zptr, (uchar *)zptr_next, rledat, rledat_next, 7 - z);
+ }
}
- lptr += xsize;
- zptr += xsize;
+ lptr = lptr_next;
+ zptr = zptr_next;
}
}
@@ -383,14 +396,17 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha
MFILE_SEEK(inf, starttab[y + z * ysize]);
rledat = MFILE_DATA(inf);
MFILE_STEP(inf, lengthtab[y + z * ysize]);
-
- expandrow2(fptr, rledat, 3 - z);
- fptr += xsize * 4;
+ const uchar *rledat_next = MFILE_DATA(inf);
+ MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next);
+ float *fptr_next = fptr + (xsize * 4);
+ dirty_flag |= expandrow2(fptr, fptr_next, rledat, rledat_next, 3 - z);
+ fptr = fptr_next;
}
}
}
else {
fptr = fbase;
+ float *fptr_next = fptr + (xsize * 4);
for (y = 0; y < ysize; y++) {
@@ -398,27 +414,31 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha
MFILE_SEEK(inf, starttab[y + z * ysize]);
rledat = MFILE_DATA(inf);
MFILE_STEP(inf, lengthtab[y + z * ysize]);
-
- expandrow2(fptr, rledat, 3 - z);
-
+ const uchar *rledat_next = MFILE_DATA(inf);
+ MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next);
+ dirty_flag |= expandrow2(fptr, fptr_next, rledat, rledat_next, 3 - z);
}
- fptr += xsize * 4;
+ fptr = fptr_next;
}
}
}
-
+#undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL
+fail_rle:
MEM_freeN(starttab);
MEM_freeN(lengthtab);
-
}
else {
+
+#define MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(p) \
+ if (UNLIKELY((p) > mem_end)) { dirty_flag |= DIRTY_FLAG_EOF; goto fail_uncompressed; } ((void)0)
+
if (bpp == 1) {
ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect);
if (ibuf->planes > 32) ibuf->planes = 32;
base = ibuf->rect;
- zbase = (unsigned int *)ibuf->zbuf;
+ zbase = (uint *)ibuf->zbuf;
MFILE_SEEK(inf, HEADER_SIZE);
rledat = MFILE_DATA(inf);
@@ -427,12 +447,13 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha
if (z < 4) lptr = base;
else if (z < 8) lptr = zbase;
-
- for (y = 0; y < ysize; y++) {
- interleaverow((uchar *)lptr, rledat, 3 - z, xsize);
- rledat += xsize;
-
+ for (y = 0; y < ysize; y++) {
+ const uchar *rledat_next = rledat + xsize;
+ const int z_ofs = 3 - z;
+ MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs);
+ interleaverow((uchar *)lptr, rledat, z_ofs, xsize);
+ rledat = rledat_next;
lptr += xsize;
}
}
@@ -450,20 +471,23 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha
for (z = 0; z < zsize; z++) {
fptr = fbase;
-
- for (y = 0; y < ysize; y++) {
- interleaverow2(fptr, rledat, 3 - z, xsize);
- rledat += xsize * 2;
-
+ for (y = 0; y < ysize; y++) {
+ const uchar *rledat_next = rledat + xsize * 2;
+ const int z_ofs = 3 - z;
+ MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs);
+ interleaverow2(fptr, rledat, z_ofs, xsize);
+ rledat = rledat_next;
fptr += xsize * 4;
}
}
}
+#undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL
+fail_uncompressed:
+ (void)0;
}
-
-
+
if (bpp == 1) {
uchar *rect;
@@ -528,6 +552,9 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha
}
+ if (dirty_flag) {
+ fprintf(stderr, "longimagedata: corrupt file content (%d)\n", dirty_flag);
+ }
ibuf->ftype = IMB_FTYPE_IMAGIC;
test_endian_zbuf(ibuf);
@@ -541,7 +568,7 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha
/* static utility functions for longimagedata */
-static void interleaverow(unsigned char *lptr, const unsigned char *cptr, int z, int n)
+static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n)
{
lptr += z;
while (n--) {
@@ -550,7 +577,7 @@ static void interleaverow(unsigned char *lptr, const unsigned char *cptr, int z,
}
}
-static void interleaverow2(float *lptr, const unsigned char *cptr, int z, int n)
+static void interleaverow2(float *lptr, const uchar *cptr, int z, int n)
{
lptr += z;
while (n--) {
@@ -560,19 +587,34 @@ static void interleaverow2(float *lptr, const unsigned char *cptr, int z, int n)
}
}
-static void expandrow2(float *optr, const unsigned char *iptr, int z)
+static int expandrow2(
+ float *optr, const float *optr_end,
+ const uchar *iptr, const uchar *iptr_end, int z)
{
- unsigned short pixel, count;
+ ushort pixel, count;
float pixel_f;
+#define EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next) \
+ if (UNLIKELY(iptr_next > iptr_end)) { goto fail; }
+
+#define EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next) \
+ if (UNLIKELY(optr_next > optr_end)) { goto fail; }
+
optr += z;
+ optr_end += z;
while (1) {
+ const uchar *iptr_next = iptr + 2;
+ EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next);
pixel = (iptr[0] << 8) | (iptr[1] << 0);
- iptr += 2;
-
+ iptr = iptr_next;
+
if (!(count = (pixel & 0x7f)) )
- return;
+ return false;
+ const float *optr_next = optr + count;
+ EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next);
if (pixel & 0x80) {
+ iptr_next = iptr + (count * 2);
+ EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next);
while (count >= 8) {
optr[0 * 4] = ((iptr[0] << 8) | (iptr[1] << 0)) / (float)0xFFFF;
optr[1 * 4] = ((iptr[2] << 8) | (iptr[3] << 0)) / (float)0xFFFF;
@@ -591,10 +633,13 @@ static void expandrow2(float *optr, const unsigned char *iptr, int z)
iptr += 2;
optr += 4;
}
+ BLI_assert(iptr == iptr_next);
}
else {
+ iptr_next = iptr + 2;
+ EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next);
pixel_f = ((iptr[0] << 8) | (iptr[1] << 0)) / (float)0xFFFF;
- iptr += 2;
+ iptr = iptr_next;
while (count >= 8) {
optr[0 * 4] = pixel_f;
@@ -612,20 +657,45 @@ static void expandrow2(float *optr, const unsigned char *iptr, int z)
*optr = pixel_f;
optr += 4;
}
+ BLI_assert(iptr == iptr_next);
}
+ BLI_assert(optr == optr_next);
}
+ return false;
+
+#undef EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL
+#undef EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL
+fail:
+ return DIRTY_FLAG_ENCODING;
}
-static void expandrow(unsigned char *optr, const unsigned char *iptr, int z)
+static int expandrow(
+ uchar *optr, const uchar *optr_end,
+ const uchar *iptr, const uchar *iptr_end, int z)
{
- unsigned char pixel, count;
+ uchar pixel, count;
+
+#define EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next) \
+ if (UNLIKELY(iptr_next > iptr_end)) { goto fail; }
+
+#define EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next) \
+ if (UNLIKELY(optr_next > optr_end)) { goto fail; }
optr += z;
+ optr_end += z;
while (1) {
- pixel = *iptr++;
+ const uchar *iptr_next = iptr + 1;
+ EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next);
+ pixel = *iptr;
+ iptr = iptr_next;
if (!(count = (pixel & 0x7f)) )
- return;
+ return false;
+ const uchar *optr_next = optr + ((int)count * 4);
+ EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next);
+
if (pixel & 0x80) {
+ iptr_next = iptr + count;
+ EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next);
while (count >= 8) {
optr[0 * 4] = iptr[0];
optr[1 * 4] = iptr[1];
@@ -643,8 +713,11 @@ static void expandrow(unsigned char *optr, const unsigned char *iptr, int z)
*optr = *iptr++;
optr += 4;
}
+ BLI_assert(iptr == iptr_next);
}
else {
+ iptr_next = iptr + 1;
+ EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next);
pixel = *iptr++;
while (count >= 8) {
optr[0 * 4] = pixel;
@@ -662,8 +735,17 @@ static void expandrow(unsigned char *optr, const unsigned char *iptr, int z)
*optr = pixel;
optr += 4;
}
+ BLI_assert(iptr == iptr_next);
}
+ BLI_assert(optr == optr_next);
}
+
+ return false;
+
+#undef EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL
+#undef EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL
+fail:
+ return DIRTY_FLAG_ENCODING;
}
/*
@@ -679,14 +761,14 @@ static void expandrow(unsigned char *optr, const unsigned char *iptr, int z)
* Added: zbuf write
*/
-static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, const char *name, int *zptr)
+static int output_iris(uint *lptr, int xsize, int ysize, int zsize, const char *name, int *zptr)
{
FILE *outf;
IMAGE *image;
int tablen, y, z, pos, len = 0;
- unsigned int *starttab, *lengthtab;
- unsigned char *rlebuf;
- unsigned int *lumbuf;
+ uint *starttab, *lengthtab;
+ uchar *rlebuf;
+ uint *lumbuf;
int rlebuflen, goodwrite;
goodwrite = 1;
@@ -696,14 +778,14 @@ static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, cons
tablen = ysize * zsize * sizeof(int);
image = (IMAGE *)MEM_mallocN(sizeof(IMAGE), "iris image");
- starttab = (unsigned int *)MEM_mallocN(tablen, "iris starttab");
- lengthtab = (unsigned int *)MEM_mallocN(tablen, "iris lengthtab");
+ starttab = (uint *)MEM_mallocN(tablen, "iris starttab");
+ lengthtab = (uint *)MEM_mallocN(tablen, "iris lengthtab");
rlebuflen = 1.05 * xsize + 10;
- rlebuf = (unsigned char *)MEM_mallocN(rlebuflen, "iris rlebuf");
- lumbuf = (unsigned int *)MEM_mallocN(xsize * sizeof(int), "iris lumbuf");
+ rlebuf = (uchar *)MEM_mallocN(rlebuflen, "iris rlebuf");
+ lumbuf = (uint *)MEM_mallocN(xsize * sizeof(int), "iris lumbuf");
memset(image, 0, sizeof(IMAGE));
- image->imagic = IMB_FTYPE_IMAGIC;
+ image->imagic = IMAGIC;
image->type = RLE(1);
if (zsize > 1)
image->dim = 3;
@@ -765,7 +847,7 @@ static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, cons
/* static utility functions for output_iris */
-static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n)
+static void lumrow(uchar *rgbptr, uchar *lumptr, int n)
{
lumptr += CHANOFFSET(0);
while (n--) {
@@ -775,9 +857,9 @@ static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n)
}
}
-static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt)
+static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int cnt)
{
- unsigned char *iptr, *ibufend, *sptr, *optr;
+ uchar *iptr, *ibufend, *sptr, *optr;
short todo, cc;
int count;
@@ -830,7 +912,7 @@ static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cn
}
}
*optr++ = 0;
- return optr - (unsigned char *)rlebuf;
+ return optr - (uchar *)rlebuf;
}
int imb_saveiris(struct ImBuf *ibuf, const char *name, int flags)
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 390f2502ee7..388c2734fe9 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -588,7 +588,7 @@ static opj_image_t *ibuftoimage(ImBuf *ibuf, opj_cparameters_t *parameters)
img_fol_t img_fol; /* only needed for cinema presets */
memset(&img_fol, 0, sizeof(img_fol_t));
- if (ibuf->float_colorspace) {
+ if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) {
/* float buffer was managed already, no need in color space conversion */
chanel_colormanage_cb = channel_colormanage_noop;
}
diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c
index 134bbe88f15..da39967a4fe 100644
--- a/source/blender/imbuf/intern/metadata.c
+++ b/source/blender/imbuf/intern/metadata.c
@@ -81,7 +81,9 @@ bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, con
void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb)
{
+ BLI_assert(dimb != simb);
if (simb->metadata) {
+ IMB_metadata_free(dimb);
dimb->metadata = IDP_CopyProperty(simb->metadata);
}
}
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index 4b49076dcd6..89955711384 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -49,7 +49,7 @@
#include "IMB_imbuf.h"
#ifdef DEBUG_MESSAGES
-# if defined __GNUC__ || defined __sun
+# if defined __GNUC__
# define PRINT(format, args ...) printf(format, ##args)
# else
# define PRINT(format, ...) printf(__VA_ARGS__)
diff --git a/source/blender/imbuf/intern/oiio/CMakeLists.txt b/source/blender/imbuf/intern/oiio/CMakeLists.txt
index c873fa3f32d..a4fb9c5aee1 100644
--- a/source/blender/imbuf/intern/oiio/CMakeLists.txt
+++ b/source/blender/imbuf/intern/oiio/CMakeLists.txt
@@ -49,6 +49,11 @@ if(WITH_OPENIMAGEIO)
${OPENIMAGEIO_INCLUDE_DIRS}
${BOOST_INCLUDE_DIR}
)
+ if(WITH_IMAGE_OPENEXR)
+ list(APPEND INC_SYS
+ ${OPENEXR_INCLUDE_DIRS}
+ )
+ endif()
add_definitions(-DWITH_OPENIMAGEIO)
endif()
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
index 11bf45418d6..b123d508f99 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
@@ -31,7 +31,7 @@
#include <set>
-#if defined(WIN32) && !defined(FREE_WINDOWS)
+#if defined(WIN32)
#include "utfconv.h"
#endif
@@ -213,7 +213,7 @@ struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspac
in = ImageInput::create(filename);
if (!in) {
std::cerr << __func__ << ": ImageInput::create() failed:" << std::endl
- << OpenImageIO::geterror() << std::endl;
+ << OIIO_NAMESPACE::geterror() << std::endl;
return NULL;
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 89e796fb7ee..1fa3b943524 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -69,7 +69,7 @@
#include <openexr_api.h>
-#if defined (WIN32) && !defined(FREE_WINDOWS)
+#if defined (WIN32)
#include "utfconv.h"
#endif
@@ -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__) && _MSC_VER < 1900
+#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && _MSC_VER < 1900
_CRTIMP void __cdecl _invalid_parameter_noinfo(void)
{
}
@@ -180,7 +180,7 @@ public:
: IStream(filename)
{
/* utf-8 file path support on windows */
-#if defined (WIN32) && !defined(FREE_WINDOWS)
+#if defined (WIN32)
wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
ifs.open(wfilename, std::ios_base::binary);
free(wfilename);
@@ -243,7 +243,7 @@ public:
: OStream(filename)
{
/* utf-8 file path support on windows */
-#if defined (WIN32) && !defined(FREE_WINDOWS)
+#if defined (WIN32)
wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
ofs.open(wfilename, std::ios_base::binary);
free(wfilename);
@@ -1026,15 +1026,16 @@ void IMB_exr_set_channel(void *handle, const char *layname, const char *passname
ExrChannel *echan;
char name[EXR_TOT_MAXNAME + 1];
- if (layname) {
+ if (layname && layname[0] != '\0') {
char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
}
- else
+ else {
BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
+ }
echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
@@ -1043,8 +1044,9 @@ void IMB_exr_set_channel(void *handle, const char *layname, const char *passname
echan->ystride = ystride;
echan->rect = rect;
}
- else
+ else {
printf("IMB_exr_set_channel error %s\n", name);
+ }
}
float *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *viewname)
@@ -1102,7 +1104,7 @@ void IMB_exr_write_channels(void *handle)
if (data->channels.first) {
const size_t num_pixels = ((size_t)data->width) * data->height;
- half *rect_half = NULL, *current_rect_half;
+ half *rect_half = NULL, *current_rect_half = NULL;
/* We allocate teporary storage for half pixels for all the channels at once. */
if (data->num_half_channels != 0) {
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index 5192e3f2d26..dded0f7aecf 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -152,7 +152,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
compression = (int)(((float)(ibuf->foptions.quality) / 11.1111f));
compression = compression < 0 ? 0 : (compression > 9 ? 9 : compression);
- if (ibuf->float_colorspace) {
+ if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) {
/* float buffer was managed already, no need in color space conversion */
chanel_colormanage_cb = channel_colormanage_noop;
}
@@ -613,11 +613,12 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
int unit_type;
png_uint_32 xres, yres;
- if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type))
+ if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type)) {
if (unit_type == PNG_RESOLUTION_METER) {
ibuf->ppm[0] = xres;
ibuf->ppm[1] = yres;
}
+ }
}
}
else {
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c
index 71e74928e20..a21468e474c 100644
--- a/source/blender/imbuf/intern/radiance_hdr.c
+++ b/source/blender/imbuf/intern/radiance_hdr.c
@@ -340,13 +340,14 @@ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufs
}
if (((beg - j) > 1) && ((beg - j) < MINRUN)) {
c2 = j + 1;
- while (rgbe_scan[c2++][i] == rgbe_scan[j][i])
+ while (rgbe_scan[c2++][i] == rgbe_scan[j][i]) {
if (c2 == beg) { /* short run */
putc((unsigned char)(128 + beg - j), file);
putc((unsigned char)(rgbe_scan[j][i]), file);
j = beg;
break;
}
+ }
}
while (j < beg) { /* write out non-run */
if ((c2 = beg - j) > 128) c2 = 128;
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 3360fd7548e..c4325caac91 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -301,8 +301,8 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height,
IMB_BlendMode mode, bool accumulate)
{
- unsigned int *drect = NULL, *orect, *srect = NULL, *dr, *or, *sr;
- float *drectf = NULL, *orectf, *srectf = NULL, *drf, *orf, *srf;
+ unsigned int *drect = NULL, *orect = NULL, *srect = NULL, *dr, *or, *sr;
+ float *drectf = NULL, *orectf = NULL, *srectf = NULL, *drf, *orf, *srf;
unsigned short *cmaskrect = curvemask, *cmr;
unsigned short *dmaskrect = dmask, *dmr;
unsigned short *texmaskrect = texmask, *tmr;
@@ -424,6 +424,7 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
else {
switch (mode) {
case IMB_BLEND_MIX:
+ case IMB_BLEND_INTERPOLATE:
func = blend_color_mix_byte;
func_float = blend_color_mix_float;
break;
@@ -563,9 +564,15 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
mask_src[0] = src[0];
mask_src[1] = src[1];
mask_src[2] = src[2];
- mask_src[3] = divide_round_i(src[3] * mask, 65535);
- func((unsigned char *)dr, (unsigned char *)or, mask_src);
+ if (mode == IMB_BLEND_INTERPOLATE) {
+ mask_src[3] = src[3];
+ blend_color_interpolate_byte((unsigned char *)dr, (unsigned char *)or, mask_src, mask / 65535.0f);
+ }
+ else {
+ mask_src[3] = divide_round_i(src[3] * mask, 65535);
+ func((unsigned char *)dr, (unsigned char *)or, mask_src);
+ }
}
}
}
@@ -588,9 +595,15 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
mask_src[0] = src[0];
mask_src[1] = src[1];
mask_src[2] = src[2];
- mask_src[3] = divide_round_i(src[3] * mask, 65535);
- func((unsigned char *)dr, (unsigned char *)or, mask_src);
+ if (mode == IMB_BLEND_INTERPOLATE) {
+ mask_src[3] = src[3];
+ blend_color_interpolate_byte((unsigned char *)dr, (unsigned char *)or, mask_src, mask / 65535.0f);
+ }
+ else {
+ mask_src[3] = divide_round_i(src[3] * mask, 65535);
+ func((unsigned char *)dr, (unsigned char *)or, mask_src);
+ }
}
}
}
@@ -642,12 +655,16 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
mask = min_ff(mask, 65535.0);
if (mask > *dmr) {
- float mask_srf[4];
-
*dmr = mask;
- mul_v4_v4fl(mask_srf, srf, mask / 65535.0f);
- func_float(drf, orf, mask_srf);
+ if (mode == IMB_BLEND_INTERPOLATE) {
+ blend_color_interpolate_float(drf, orf, srf, mask / 65535.0f);
+ }
+ else {
+ float mask_srf[4];
+ mul_v4_v4fl(mask_srf, srf, mask / 65535.0f);
+ func_float(drf, orf, mask_srf);
+ }
}
}
}
@@ -664,11 +681,15 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
mask = min_ff(mask, 65535.0);
if (srf[3] && (mask > 0.0f)) {
- float mask_srf[4];
-
- mul_v4_v4fl(mask_srf, srf, mask / 65535.0f);
+ if (mode == IMB_BLEND_INTERPOLATE) {
+ blend_color_interpolate_float(drf, orf, srf, mask / 65535.0f);
+ }
+ else {
+ float mask_srf[4];
+ mul_v4_v4fl(mask_srf, srf, mask / 65535.0f);
+ func_float(drf, orf, mask_srf);
+ }
- func_float(drf, orf, mask_srf);
}
}
}
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 4368a428186..98aa7c5353b 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -813,26 +813,51 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags)
}
/* copy pixel data. While copying, we flip the image vertically. */
+ const int channels_in_float = ibuf->channels ? ibuf->channels : 4;
for (x = 0; x < ibuf->x; x++) {
for (y = 0; y < ibuf->y; y++) {
- from_i = 4 * (y * ibuf->x + x);
+ from_i = ((size_t)channels_in_float) * (y * ibuf->x + x);
to_i = samplesperpixel * ((ibuf->y - y - 1) * ibuf->x + x);
if (pixels16) {
/* convert from float source */
float rgb[4];
-
- if (ibuf->float_colorspace) {
- /* float buffer was managed already, no need in color space conversion */
- copy_v3_v3(rgb, &fromf[from_i]);
+
+ if (channels_in_float == 3 || channels_in_float == 4) {
+ if (ibuf->float_colorspace ||
+ (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA))
+ {
+ /* Float buffer was managed already, no need in color
+ * space conversion.
+ */
+ copy_v3_v3(rgb, &fromf[from_i]);
+ }
+ else {
+ /* Standard linear-to-srgb conversion if float buffer
+ * wasn't managed.
+ */
+ linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]);
+ }
+ if (channels_in_float == 4) {
+ rgb[3] = fromf[from_i + 3];
+ }
+ else {
+ rgb[3] = 1.0f;
+ }
}
else {
- /* standard linear-to-srgb conversion if float buffer wasn't managed */
- linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]);
+ if (ibuf->float_colorspace ||
+ (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA))
+ {
+ rgb[0] = fromf[from_i];
+ }
+ else {
+ rgb[0] = linearrgb_to_srgb(fromf[from_i]);
+ }
+ rgb[1] = rgb[2] = rgb[0];
+ rgb[3] = 1.0f;
}
- rgb[3] = fromf[from_i + 3];
-
for (i = 0; i < samplesperpixel; i++, to_i++)
to16[to_i] = FTOUSHORT(rgb[i]);
}
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index ba8480b636f..76a44aa81f7 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -52,10 +52,6 @@
#include "IMB_anim.h"
-#ifdef WITH_QUICKTIME
-#include "quicktime_import.h"
-#endif
-
#ifdef WITH_FFMPEG
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
@@ -107,28 +103,6 @@ const char *imb_ext_image_filepath_only[] = {
NULL
};
-const char *imb_ext_image_qt[] = {
- ".gif",
- ".psd",
- ".pct", ".pict",
- ".pntg",
- ".qtif",
- NULL
-};
-
-#if 0 /* UNUSED */
-const char *imb_ext_movie_qt[] = {
- ".avi",
- ".flc",
- ".dv",
- ".r3d",
- ".mov",
- ".movie",
- ".mv",
- NULL
-};
-#endif
-
const char *imb_ext_movie[] = {
".avi",
".flc",
@@ -247,13 +221,6 @@ static int isavi(const char *name)
#endif
}
-#ifdef WITH_QUICKTIME
-static int isqtime(const char *name)
-{
- return anim_is_quicktime(name);
-}
-#endif
-
#ifdef WITH_FFMPEG
/* BLI_vsnprintf in ffmpeg_log_callback() causes invalid warning */
@@ -383,9 +350,6 @@ int imb_get_anim_type(const char *name)
if (UTIL_DEBUG) printf("%s: %s\n", __func__, name);
#ifndef _WIN32
-# ifdef WITH_QUICKTIME
- if (isqtime(name)) return (ANIM_QTIME);
-# endif
# ifdef WITH_FFMPEG
/* stat test below fails on large files > 4GB */
if (isffmpeg(name)) return (ANIM_FFMPEG);
@@ -401,9 +365,6 @@ int imb_get_anim_type(const char *name)
if (((st.st_mode) & S_IFMT) != S_IFREG) return(0);
if (ismovie(name)) return (ANIM_MOVIE);
-# ifdef WITH_QUICKTIME
- if (isqtime(name)) return (ANIM_QTIME);
-# endif
# ifdef WITH_FFMPEG
if (isffmpeg(name)) return (ANIM_FFMPEG);
# endif
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index feeb2d5e4d7..b2a3cb4f9bc 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -82,8 +82,6 @@ enum {
IDP_FLOAT = 2,
IDP_ARRAY = 5,
IDP_GROUP = 6,
- /* the ID link property type hasn't been implemented yet, this will require
- * some cleanup of blenkernel, most likely. */
IDP_ID = 7,
IDP_DOUBLE = 8,
IDP_IDPARRAY = 9,
@@ -129,8 +127,7 @@ typedef struct ID {
/**
* LIB_TAG_... tags (runtime only, cleared at read time).
*/
- short tag;
- short pad_s1;
+ int tag;
int us;
int icon_id;
IDProperty *properties;
@@ -155,8 +152,9 @@ typedef struct Library {
struct PackedFile *packedfile;
+ /* Temp data needed by read/write code. */
int temp_index;
- int _pad;
+ short versionfile, subversionfile; /* see BLENDER_VERSION, BLENDER_SUBVERSION, needed for do_versions */
} Library;
enum eIconSizes {
@@ -276,6 +274,7 @@ typedef enum ID_Type {
#define ID_FAKE_USERS(id) ((((ID *)id)->flag & LIB_FAKEUSER) ? 1 : 0)
#define ID_REAL_USERS(id) (((ID *)id)->us - ID_FAKE_USERS(id))
+#define ID_EXTRA_USERS(id) (((ID *)id)->tag & LIB_TAG_EXTRAUSER ? 1 : 0)
#define ID_CHECK_UNDO(id) ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM))
@@ -288,11 +287,11 @@ typedef enum ID_Type {
#ifdef GS
# undef GS
#endif
-#define GS(a) (CHECK_TYPE_ANY(a, char *, const char *, char [66], const char[66]), (*((const short *)(a))))
+#define GS(a) (CHECK_TYPE_ANY(a, char *, const char *, char [66], const char[66]), (ID_Type)(*((const short *)(a))))
-#define ID_NEW(a) if ( (a) && (a)->id.newid ) (a) = (void *)(a)->id.newid
-#define ID_NEW_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; }
-#define ID_NEW_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; }
+#define ID_NEW_SET(_id, _idn) \
+ (((ID *)(_id))->newid = (ID *)(_idn), ((ID *)(_id))->newid->tag |= LIB_TAG_NEW, (void *)((ID *)(_id))->newid)
+#define ID_NEW_REMAP(a) if ((a) && (a)->id.newid) (a) = (void *)(a)->id.newid
/* id->flag (persitent). */
enum {
@@ -336,7 +335,8 @@ enum {
/* tag datablock has having actually increased usercount for the extra virtual user. */
LIB_TAG_EXTRAUSER_SET = 1 << 7,
- /* RESET_AFTER_USE tag newly duplicated/copied IDs. */
+ /* RESET_AFTER_USE tag newly duplicated/copied IDs.
+ * Also used internally in readfile.c to mark datablocks needing do_versions. */
LIB_TAG_NEW = 1 << 8,
/* RESET_BEFORE_USE free test flag.
* TODO make it a RESET_AFTER_USE too. */
@@ -349,6 +349,13 @@ enum {
LIB_TAG_ID_RECALC_DATA = 1 << 13,
LIB_TAG_ANIM_NO_RECALC = 1 << 14,
LIB_TAG_ID_RECALC_ALL = (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA),
+
+ /* RESET_NEVER tag datablock for freeing etc. behavior (usually set when copying real one into temp/runtime one). */
+ LIB_TAG_NO_MAIN = 1 << 16, /* Datablock is not listed in Main database. */
+ LIB_TAG_NO_USER_REFCOUNT = 1 << 17, /* Datablock does not refcount usages of other IDs. */
+ /* Datablock was not allocated by standard system (BKE_libblock_alloc), do not free its memory
+ * (usual type-specific freeing is called though). */
+ LIB_TAG_NOT_ALLOCATED = 1 << 18,
};
/* To filter ID types (filter_id) */
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index f3df9090d41..d49960771d0 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -76,6 +76,8 @@ typedef struct bMotionPath {
int start_frame; /* for drawing paths, the start frame number */
int end_frame; /* for drawing paths, the end frame number */
+ float color[3]; /* optional custom color */
+ int line_thickness; /* line thickness */
int flag; /* baking settings - eMotionPath_Flag */
} bMotionPath;
@@ -84,7 +86,11 @@ typedef enum eMotionPath_Flag {
/* (for bones) path represents the head of the bone */
MOTIONPATH_FLAG_BHEAD = (1 << 0),
/* motion path is being edited */
- MOTIONPATH_FLAG_EDIT = (1 << 1)
+ MOTIONPATH_FLAG_EDIT = (1 << 1),
+ /* Custom colors */
+ MOTIONPATH_FLAG_CUSTOM = (1 << 2),
+ /* Draw lines or only points */
+ MOTIONPATH_FLAG_LINES = (1 << 3)
} eMotionPath_Flag;
/* Visualization General --------------------------- */
@@ -508,7 +514,7 @@ typedef enum eActionGroup_Flag {
AGRP_MODIFIERS_OFF = (1 << 7),
AGRP_TEMP = (1 << 30),
- AGRP_MOVED = (1 << 31)
+ AGRP_MOVED = (1u << 31)
} eActionGroup_Flag;
@@ -751,7 +757,7 @@ typedef enum ACHAN_FLAG {
ACHAN_EXPANDED = (1 << 4),
ACHAN_SHOWIPO = (1 << 5),
ACHAN_SHOWCONS = (1 << 6),
- ACHAN_MOVED = (1 << 31)
+ ACHAN_MOVED = (1u << 31)
} ACHAN_FLAG;
#endif /* __DNA_ACTION_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index e50a2637fff..935a893f689 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -685,7 +685,7 @@ typedef enum eNlaStrip_Flag {
/* temporary editing flags */
/* NLA-Strip is really just a temporary meta used to facilitate easier transform code */
NLASTRIP_FLAG_TEMP_META = (1<<30),
- NLASTRIP_FLAG_EDIT_TOUCHED = (1<<31)
+ NLASTRIP_FLAG_EDIT_TOUCHED = (1u << 31)
} eNlaStrip_Flag;
/* NLA Strip Type */
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index f4a1677efc4..c285b44c939 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -95,8 +95,12 @@ typedef struct Brush {
float plane_offset; /* offset for plane brushes (clay, flatten, fill, scrape) */
int gradient_spacing;
- int gradient_stroke_mode; /* source for stroke color gradient application */
- int gradient_fill_mode; /* source for fill tool color gradient application */
+ char gradient_stroke_mode; /* source for stroke color gradient application */
+ char gradient_fill_mode; /* source for fill tool color gradient application */
+
+ char pad;
+ char falloff_shape; /* Projection shape (sphere, circle) */
+ float falloff_angle;
char sculpt_tool; /* active sculpt tool */
char vertexpaint_tool; /* active vertex/weight paint blend mode (poorly named) */
@@ -181,13 +185,13 @@ typedef enum BrushGradientSourceFill {
/* Brush.flag */
typedef enum BrushFlags {
BRUSH_AIRBRUSH = (1 << 0),
-// BRUSH_TORUS = (1 << 1), deprecated, use paint->symmetry_flags & PAINT_TILE_*
+ BRUSH_FLAG_DEPRECATED_1 = (1 << 1),
BRUSH_ALPHA_PRESSURE = (1 << 2),
BRUSH_SIZE_PRESSURE = (1 << 3),
BRUSH_JITTER_PRESSURE = (1 << 4),
BRUSH_SPACING_PRESSURE = (1 << 5),
- BRUSH_UNUSED = (1 << 6),
-// BRUSH_RAKE = (1 << 7), deprecated, use brush_angle_mode
+ BRUSH_FLAG_DEPRECATED_2 = (1 << 6),
+ BRUSH_FLAG_DEPRECATED_3 = (1 << 7),
BRUSH_ANCHORED = (1 << 8),
BRUSH_DIR_IN = (1 << 9),
BRUSH_SPACE = (1 << 10),
@@ -197,6 +201,7 @@ typedef enum BrushFlags {
BRUSH_LOCK_ALPHA = (1 << 14),
BRUSH_ORIGINAL_NORMAL = (1 << 15),
BRUSH_OFFSET_PRESSURE = (1 << 16),
+ BRUSH_FLAG_DEPRECATED_4 = (1 << 17),
BRUSH_SPACE_ATTEN = (1 << 18),
BRUSH_ADAPTIVE_SPACE = (1 << 19),
BRUSH_LOCK_SIZE = (1 << 20),
@@ -204,13 +209,13 @@ typedef enum BrushFlags {
BRUSH_EDGE_TO_EDGE = (1 << 22),
BRUSH_DRAG_DOT = (1 << 23),
BRUSH_INVERSE_SMOOTH_PRESSURE = (1 << 24),
-// BRUSH_RANDOM_ROTATION = (1 << 25), deprecated, use brush_angle_mode
+ BRUSH_FRONTFACE_FALLOFF = (1 << 25),
BRUSH_PLANE_TRIM = (1 << 26),
BRUSH_FRONTFACE = (1 << 27),
BRUSH_CUSTOM_ICON = (1 << 28),
BRUSH_LINE = (1 << 29),
BRUSH_ABSOLUTE_JITTER = (1 << 30),
- BRUSH_CURVE = (1 << 31)
+ BRUSH_CURVE = (1u << 31)
} BrushFlags;
typedef enum {
@@ -315,7 +320,21 @@ enum {
PAINT_BLEND_MUL = 3,
PAINT_BLEND_BLUR = 4,
PAINT_BLEND_LIGHTEN = 5,
- PAINT_BLEND_DARKEN = 6
+ PAINT_BLEND_DARKEN = 6,
+ PAINT_BLEND_AVERAGE = 7,
+ PAINT_BLEND_SMEAR = 8,
+ PAINT_BLEND_COLORDODGE = 9,
+ PAINT_BLEND_DIFFERENCE = 10,
+ PAINT_BLEND_SCREEN = 11,
+ PAINT_BLEND_HARDLIGHT = 12,
+ PAINT_BLEND_OVERLAY = 13,
+ PAINT_BLEND_SOFTLIGHT = 14,
+ PAINT_BLEND_EXCLUSION = 15,
+ PAINT_BLEND_LUMINOCITY = 16,
+ PAINT_BLEND_SATURATION = 17,
+ PAINT_BLEND_HUE = 18,
+ PAINT_BLEND_ALPHA_SUB = 19,
+ PAINT_BLEND_ALPHA_ADD = 20,
};
typedef enum {
@@ -329,6 +348,12 @@ typedef enum BlurKernelType {
KERNEL_BOX
} BlurKernelType;
+/* Brush.falloff_shape */
+enum {
+ PAINT_FALLOFF_SHAPE_SPHERE = 0,
+ PAINT_FALLOFF_SHAPE_TUBE = 1,
+};
+
#define MAX_BRUSH_PIXEL_RADIUS 500
#endif /* __DNA_BRUSH_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h
index 46b1adf2725..a353c94ae64 100644
--- a/source/blender/makesdna/DNA_cachefile_types.h
+++ b/source/blender/makesdna/DNA_cachefile_types.h
@@ -47,10 +47,12 @@ enum {
CACHEFILE_KEYFRAME_DRAWN = (1 << 0),
};
+/* Representation of an object's path inside the Alembic file.
+ * Note that this is not a file path. */
typedef struct AlembicObjectPath {
struct AlembicObjectPath *next, *prev;
- char path[1024]; /* 1024 = FILE_MAX, might use PATH_MAX in the future. */
+ char path[4096];
} AlembicObjectPath;
typedef struct CacheFile {
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 23b73424da5..0364d855f69 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -244,6 +244,7 @@ typedef struct bGPDlayer {
float inverse[4][4]; /* inverse matrix (only used if parented) */
char parsubstr[64]; /* String describing subobject info, MAX_ID_NAME-2 */
short partype, pad;
+
float tintcolor[4]; /* Color used to tint layer, alpha value is used as factor */
float opacity; /* Opacity of the layer */
} bGPDlayer;
@@ -275,7 +276,9 @@ typedef enum eGPDlayer_Flag {
/* Use high quality fill (instead of buggy legacy OpenGL Fill) */
GP_LAYER_HQ_FILL = (1 << 11),
/* Unlock color */
- GP_LAYER_UNLOCK_COLOR = (1 << 12)
+ GP_LAYER_UNLOCK_COLOR = (1 << 12),
+ /* always show onion skins (i.e. even during renders/animation playback) */
+ GP_LAYER_GHOST_ALWAYS = (1 << 13),
} eGPDlayer_Flag;
/* Grease-Pencil Annotations - 'DataBlock' */
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 621807d111c..3676066a399 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -164,8 +164,8 @@ typedef struct MLoop {
* MEdge *ed = &medge[mloop[lt->tri[j]].e];
* unsigned int tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
*
- * if (ELEM(ed->v1, tri_edge[0], tri_edge[1]) &&
- * ELEM(ed->v2, tri_edge[0], tri_edge[1]))
+ * if (((ed->v1 == tri_edge[0]) && (ed->v1 == tri_edge[1])) ||
+ * ((ed->v1 == tri_edge[1]) && (ed->v1 == tri_edge[0])))
* {
* printf("real edge found %u %u\n", tri_edge[0], tri_edge[1]);
* }
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index f95533a88f9..64856b2eb76 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -86,6 +86,7 @@ typedef enum ModifierType {
eModifierType_NormalEdit = 50,
eModifierType_CorrectiveSmooth = 51,
eModifierType_MeshSequenceCache = 52,
+ eModifierType_SurfaceDeform = 53,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -97,7 +98,7 @@ typedef enum ModifierMode {
eModifierMode_Expanded = (1 << 4),
eModifierMode_Virtual = (1 << 5),
eModifierMode_ApplyOnSpline = (1 << 6),
- eModifierMode_DisableTemporary = (1 << 31)
+ eModifierMode_DisableTemporary = (1u << 31)
} ModifierMode;
typedef struct ModifierData {
@@ -276,6 +277,8 @@ typedef struct MirrorModifierData {
short axis DNA_DEPRECATED; /* deprecated, use flag instead */
short flag;
float tolerance;
+ float uv_offset[2];
+ float uv_offset_copy[2];
struct Object *mirror_ob;
} MirrorModifierData;
@@ -652,7 +655,8 @@ typedef struct BooleanModifierData {
struct Object *object;
char operation;
char solver;
- char pad[2];
+ char pad;
+ char bm_flag;
float double_threshold;
} BooleanModifierData;
@@ -667,6 +671,13 @@ typedef enum {
eBooleanModifierSolver_BMesh = 1,
} BooleanSolver;
+/* bm_flag (only used when G_DEBUG) */
+enum {
+ eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 0),
+ eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 1),
+ eBooleanModifierBMeshFlag_BMesh_NoConnectRegions = (1 << 2),
+};
+
typedef struct MDefInfluence {
int vertex;
float weight;
@@ -922,9 +933,10 @@ typedef struct ScrewModifierData {
unsigned int iter;
float screw_ofs;
float angle;
- char axis;
- char pad;
+ float merge_dist;
short flag;
+ char axis;
+ char pad[5];
} ScrewModifierData;
enum {
@@ -935,6 +947,7 @@ enum {
MOD_SCREW_SMOOTH_SHADING = (1 << 5),
MOD_SCREW_UV_STRETCH_U = (1 << 6),
MOD_SCREW_UV_STRETCH_V = (1 << 7),
+ MOD_SCREW_MERGE = (1 << 8),
};
typedef struct OceanModifierData {
@@ -1513,7 +1526,7 @@ enum {
MOD_DATATRANSFER_USE_VERT = 1 << 28,
MOD_DATATRANSFER_USE_EDGE = 1 << 29,
MOD_DATATRANSFER_USE_LOOP = 1 << 30,
- MOD_DATATRANSFER_USE_POLY = 1 << 31,
+ MOD_DATATRANSFER_USE_POLY = 1u << 31,
};
/* Set Split Normals modifier */
@@ -1570,6 +1583,46 @@ enum {
MOD_MESHSEQ_READ_COLOR = (1 << 3),
};
+typedef struct SDefBind {
+ unsigned int *vert_inds;
+ unsigned int numverts;
+ int mode;
+ float *vert_weights;
+ float normal_dist;
+ float influence;
+} SDefBind;
+
+typedef struct SDefVert {
+ SDefBind *binds;
+ unsigned int numbinds;
+ char pad[4];
+} SDefVert;
+
+typedef struct SurfaceDeformModifierData {
+ ModifierData modifier;
+
+ struct Object *target; /* bind target object */
+ SDefVert *verts; /* vertex bind data */
+ float falloff;
+ unsigned int numverts, numpoly;
+ int flags;
+ float mat[4][4];
+} SurfaceDeformModifierData;
+
+/* Surface Deform modifier flags */
+enum {
+ MOD_SDEF_BIND = (1 << 0),
+ MOD_SDEF_USES_LOOPTRI = (1 << 1),
+ MOD_SDEF_HAS_CONCAVE = (1 << 2),
+};
+
+/* Surface Deform vertex bind modes */
+enum {
+ MOD_SDEF_MODE_LOOPTRI = 0,
+ MOD_SDEF_MODE_NGON = 1,
+ MOD_SDEF_MODE_CENTROID = 2,
+};
+
#define MOD_MESHSEQ_READ_ALL \
(MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 46b30f41f5b..e6bc315b728 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -111,7 +111,7 @@ typedef struct bNodeSocket {
short stack_index; /* local stack index */
/* XXX deprecated, kept for forward compatibility */
short stack_type DNA_DEPRECATED;
- int pad;
+ char draw_shape, pad[3];
void *cache; /* cached data from execution */
@@ -143,6 +143,13 @@ typedef enum eNodeSocketDatatype {
SOCK_STRING = 7
} eNodeSocketDatatype;
+/* socket shape */
+typedef enum eNodeSocketDrawShape {
+ SOCK_DRAW_SHAPE_CIRCLE = 0,
+ SOCK_DRAW_SHAPE_SQUARE = 1,
+ SOCK_DRAW_SHAPE_DIAMOND = 2
+} eNodeSocketDrawShape;
+
/* socket side (input/output) */
typedef enum eNodeSocketInOut {
SOCK_IN = 1,
@@ -569,9 +576,9 @@ typedef struct NodeEllipseMask {
/* layer info for image node outputs */
typedef struct NodeImageLayer {
/* index in the Image->layers->passes lists */
- int pass_index;
- /* render pass flag, in case this is an original render pass */
- int pass_flag;
+ int pass_index DNA_DEPRECATED;
+ /* render pass name */
+ char pass_name[64]; /* amount defined in openexr_multi.h */
} NodeImageLayer;
typedef struct NodeBlurData {
@@ -595,6 +602,7 @@ typedef struct NodeBilateralBlurData {
short iter, pad;
} NodeBilateralBlurData;
+/* NOTE: Only for do-version code. */
typedef struct NodeHueSat {
float hue, sat, val;
} NodeHueSat;
@@ -667,7 +675,8 @@ typedef struct NodeScriptDict {
/* qdn: glare node */
typedef struct NodeGlare {
char quality, type, iter;
- char angle, pad_c1, size, pad[2];
+ /* XXX angle is only kept for backward/forward compatibility, was used for two different things, see T50736. */
+ char angle DNA_DEPRECATED, pad_c1, size, star_45, streaks;
float colmod, mix, threshold, fade;
float angle_ofs, pad_f1;
} NodeGlare;
@@ -811,7 +820,10 @@ typedef struct NodeShaderTexPointDensity {
short color_source;
short ob_color_source;
char vertex_attribute_name[64]; /* vertex attribute layer for color source, MAX_CUSTOMDATA_LAYER_NAME */
+ /* Used at runtime only by sampling RNA API. */
PointDensity pd;
+ int cached_resolution;
+ int pad2;
} NodeShaderTexPointDensity;
/* TEX_output */
diff --git a/source/blender/makesdna/DNA_object_fluidsim.h b/source/blender/makesdna/DNA_object_fluidsim.h
index a714195dd5d..846d5788d63 100644
--- a/source/blender/makesdna/DNA_object_fluidsim.h
+++ b/source/blender/makesdna/DNA_object_fluidsim.h
@@ -179,6 +179,7 @@ typedef struct FluidsimSettings {
#define OB_FLUIDSIM_ACTIVE (1 << 1)
#define OB_FLUIDSIM_OVERRIDE_TIME (1 << 2)
+#define OB_FLUIDSIM_SURF_DIR_DEFAULT "cache_fluid"
#define OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME "fluidsurface_preview_####.bobj.gz"
#define OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME "fluidsurface_final_####.bobj.gz"
#define OB_FLUIDSIM_SURF_FINAL_VEL_FNAME "fluidsurface_final_####.bvel.gz"
diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h
index 59acefeffe4..ed14c4b9311 100644
--- a/source/blender/makesdna/DNA_object_force.h
+++ b/source/blender/makesdna/DNA_object_force.h
@@ -372,6 +372,7 @@ typedef struct SoftBody {
#define PFIELD_DO_ROTATION (1<<15)
#define PFIELD_GUIDE_PATH_WEIGHT (1<<16) /* apply curve weights */
#define PFIELD_SMOKE_DENSITY (1<<17) /* multiply smoke force by density */
+#define PFIELD_GRAVITATION (1<<18) /* used for (simple) force */
/* pd->falloff */
#define PFIELD_FALL_SPHERE 0
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index d24c7faa9f5..0f341aa4001 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -335,6 +335,8 @@ typedef struct DupliObject {
/* particle this dupli was generated from */
struct ParticleSystem *particle_system;
+ unsigned int random_id;
+ unsigned int pad;
} DupliObject;
/* **************** OBJECT ********************* */
@@ -681,6 +683,9 @@ typedef enum ObjectMode {
/* any mode where the brush system is used */
#define OB_MODE_ALL_PAINT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)
+/* any mode that uses ob->sculpt */
+#define OB_MODE_ALL_SCULPT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)
+
#define MAX_DUPLI_RECUR 8
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index 1deb9bf3787..f6bed37dfa2 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -323,7 +323,7 @@ typedef struct ParticleSystem {
struct ParticleDrawData *pdd;
float dt_frac; /* current time step, as a fraction of a frame */
- float _pad; /* spare capacity */
+ float lattice_strength; /* influence of the lattice modifier */
} ParticleSystem;
typedef enum eParticleDrawFlag {
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index f5e71ae59a9..3ad75142c46 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -99,42 +99,6 @@ typedef struct AviCodecData {
char avicodecname[128];
} AviCodecData;
-typedef struct QuicktimeCodecData {
- /*Old quicktime implementation compatibility fields, read only in 2.5 - deprecated*/
- void *cdParms; /* codec/compressor options */
- void *pad; /* padding */
-
- unsigned int cdSize; /* size of cdParms buffer */
- unsigned int pad2; /* padding */
-
- char qtcodecname[128];
-} QuicktimeCodecData;
-
-typedef struct QuicktimeCodecSettings {
- /* Codec settings detailed for 2.5 implementation*/
- int codecType; /* Types defined in quicktime_export.h */
- int codecSpatialQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */
-
- /* Settings not available in current QTKit API */
- int codec;
- int codecFlags;
- int colorDepth;
- int codecTemporalQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */
- int minSpatialQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */
- int minTemporalQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */
- int keyFrameRate;
- int bitRate; /* bitrate in bps */
-
- /* Audio Codec settings */
- int audiocodecType;
- int audioSampleRate;
- short audioBitDepth;
- short audioChannels;
- int audioCodecFlags;
- int audioBitRate;
- int pad1;
-} QuicktimeCodecSettings;
-
typedef enum FFMpegPreset {
FFM_PRESET_NONE,
FFM_PRESET_ULTRAFAST,
@@ -229,7 +193,9 @@ typedef struct SceneRenderLayer {
int samples;
float pass_alpha_threshold;
-
+
+ IDProperty *prop;
+
struct FreestyleConfig freestyleConfig;
} SceneRenderLayer;
@@ -283,9 +249,43 @@ typedef enum ScenePassType {
SCE_PASS_SUBSURFACE_DIRECT = (1 << 28),
SCE_PASS_SUBSURFACE_INDIRECT = (1 << 29),
SCE_PASS_SUBSURFACE_COLOR = (1 << 30),
- SCE_PASS_DEBUG = (1 << 31), /* This is a virtual pass. */
} ScenePassType;
+#define RE_PASSNAME_COMBINED "Combined"
+#define RE_PASSNAME_Z "Depth"
+#define RE_PASSNAME_VECTOR "Vector"
+#define RE_PASSNAME_NORMAL "Normal"
+#define RE_PASSNAME_UV "UV"
+#define RE_PASSNAME_RGBA "Color"
+#define RE_PASSNAME_EMIT "Emit"
+#define RE_PASSNAME_DIFFUSE "Diffuse"
+#define RE_PASSNAME_SPEC "Spec"
+#define RE_PASSNAME_SHADOW "Shadow"
+
+#define RE_PASSNAME_AO "AO"
+#define RE_PASSNAME_ENVIRONMENT "Env"
+#define RE_PASSNAME_INDIRECT "Indirect"
+#define RE_PASSNAME_REFLECT "Reflect"
+#define RE_PASSNAME_REFRACT "Refract"
+#define RE_PASSNAME_INDEXOB "IndexOB"
+#define RE_PASSNAME_INDEXMA "IndexMA"
+#define RE_PASSNAME_MIST "Mist"
+
+#define RE_PASSNAME_RAYHITS "RayHits"
+#define RE_PASSNAME_DIFFUSE_DIRECT "DiffDir"
+#define RE_PASSNAME_DIFFUSE_INDIRECT "DiffInd"
+#define RE_PASSNAME_DIFFUSE_COLOR "DiffCol"
+#define RE_PASSNAME_GLOSSY_DIRECT "GlossDir"
+#define RE_PASSNAME_GLOSSY_INDIRECT "GlossInd"
+#define RE_PASSNAME_GLOSSY_COLOR "GlossCol"
+#define RE_PASSNAME_TRANSM_DIRECT "TransDir"
+#define RE_PASSNAME_TRANSM_INDIRECT "TransInd"
+#define RE_PASSNAME_TRANSM_COLOR "TransCol"
+
+#define RE_PASSNAME_SUBSURFACE_DIRECT "SubsurfaceDir"
+#define RE_PASSNAME_SUBSURFACE_INDIRECT "SubsurfaceInd"
+#define RE_PASSNAME_SUBSURFACE_COLOR "SubsurfaceCol"
+
/* note, srl->passflag is treestore element 'nr' in outliner, short still... */
/* View - MultiView */
@@ -420,7 +420,7 @@ typedef struct ImageFormatData {
#define R_IMF_IMTYPE_AVIJPEG 16
#define R_IMF_IMTYPE_PNG 17
/* #define R_IMF_IMTYPE_AVICODEC 18 */ /* avicodec is nomore */
-#define R_IMF_IMTYPE_QUICKTIME 19
+/* #define R_IMF_IMTYPE_QUICKTIME 19 */ /* quicktime is nomore */
#define R_IMF_IMTYPE_BMP 20
#define R_IMF_IMTYPE_RADHDR 21
#define R_IMF_IMTYPE_TIFF 22
@@ -549,8 +549,6 @@ typedef struct RenderData {
struct ImageFormatData im_format;
struct AviCodecData *avicodecdata;
- struct QuicktimeCodecData *qtcodecdata;
- struct QuicktimeCodecSettings qtcodecsettings;
struct FFMpegCodecData ffcodecdata;
int cfra, sfra, efra; /* frames as in 'images' */
@@ -715,7 +713,7 @@ typedef struct RenderData {
/* sequencer options */
char seq_prev_type;
- char seq_rend_type;
+ char seq_rend_type; /* UNUSED! */
char seq_flag; /* flag use for sequence render/draw */
char pad5[5];
@@ -754,14 +752,13 @@ typedef struct RenderData {
struct BakeData bake;
int preview_start_resolution;
+ short preview_pixel_size;
/* Type of the debug pass to use.
* Only used when built with debug passes support.
*/
short debug_pass_type;
- short pad;
-
/* MultiView */
ListBase views; /* SceneRenderView */
short actview;
@@ -1120,23 +1117,15 @@ typedef struct UvSculpt {
/* Vertex Paint */
typedef struct VPaint {
Paint paint;
-
- short flag, pad;
- int tot; /* allocation size of prev buffers */
- unsigned int *vpaint_prev; /* previous mesh colors */
- struct MDeformVert *wpaint_prev; /* previous vertex weights */
-
- void *paintcursor; /* wm handle */
+ char flag;
+ char pad[3];
+ int radial_symm[3]; /* For mirrored painting */
} VPaint;
/* VPaint.flag */
enum {
- // VP_COLINDEX = (1 << 0), /* only paint onto active material*/ /* deprecated since before 2.49 */
- // VP_AREA = (1 << 1), /* deprecated since 2.70 */
- VP_NORMALS = (1 << 3),
- VP_SPRAY = (1 << 4),
- // VP_MIRROR_X = (1 << 5), /* deprecated in 2.5x use (me->editflag & ME_EDIT_MIRROR_X) */
- VP_ONLYVGROUP = (1 << 7) /* weight paint only */
+ /* weight paint only */
+ VP_FLAG_VGROUP_RESTRICT = (1 << 7)
};
/* ------------------------------------------- */
@@ -1212,12 +1201,51 @@ typedef enum eGP_BrushEdit_SettingsFlag {
GP_BRUSHEDIT_FLAG_APPLY_STRENGTH = (1 << 2),
/* apply brush to thickness */
GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3),
+} eGP_BrushEdit_SettingsFlag;
+
+
+/* Settings for GP Interpolation Operators */
+typedef struct GP_Interpolate_Settings {
+ short flag; /* eGP_Interpolate_SettingsFlag */
+
+ char type; /* eGP_Interpolate_Type - Interpolation Mode */
+ char easing; /* eBezTriple_Easing - Easing mode (if easing equation used) */
+
+ float back; /* BEZT_IPO_BACK */
+ float amplitude, period; /* BEZT_IPO_ELASTIC */
+
+ struct CurveMapping *custom_ipo; /* custom interpolation curve (for use with GP_IPO_CURVEMAP) */
+} GP_Interpolate_Settings;
+
+/* GP_Interpolate_Settings.flag */
+typedef enum eGP_Interpolate_SettingsFlag {
/* apply interpolation to all layers */
- GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS = (1 << 4),
+ GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS = (1 << 0),
/* apply interpolation to only selected */
- GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED = (1 << 5)
+ GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED = (1 << 1),
+} eGP_Interpolate_SettingsFlag;
+
+/* GP_Interpolate_Settings.type */
+typedef enum eGP_Interpolate_Type {
+ /* Traditional Linear Interpolation */
+ GP_IPO_LINEAR = 0,
+
+ /* CurveMap Defined Interpolation */
+ GP_IPO_CURVEMAP = 1,
+
+ /* Easing Equations */
+ GP_IPO_BACK = 3,
+ GP_IPO_BOUNCE = 4,
+ GP_IPO_CIRC = 5,
+ GP_IPO_CUBIC = 6,
+ GP_IPO_ELASTIC = 7,
+ GP_IPO_EXPO = 8,
+ GP_IPO_QUAD = 9,
+ GP_IPO_QUART = 10,
+ GP_IPO_QUINT = 11,
+ GP_IPO_SINE = 12,
+} eGP_Interpolate_Type;
-} eGP_BrushEdit_SettingsFlag;
/* *************************************************************** */
/* Transform Orientations */
@@ -1435,7 +1463,10 @@ typedef struct ToolSettings {
/* Grease Pencil Sculpt */
struct GP_BrushEdit_Settings gp_sculpt;
-
+
+ /* Grease Pencil Interpolation Tool(s) */
+ struct GP_Interpolate_Settings gp_interpolate;
+
/* Grease Pencil Drawing Brushes (bGPDbrush) */
ListBase gp_brushes;
@@ -1590,8 +1621,7 @@ typedef struct Scene {
struct Object *obedit; /* name replaces old G.obedit */
float cursor[3]; /* 3d cursor location */
- float twcent[3]; /* center for transform widget */
- float twmin[3], twmax[3]; /* boundbox of selection for transform widget */
+ char _pad[4];
unsigned int lay; /* bitflags for layer visibility */
int layact; /* active layer */
@@ -1652,6 +1682,8 @@ typedef struct Scene {
/* Movie Tracking */
struct MovieClip *clip; /* active movie clip */
+ void *pad4;
+
uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update() */
uint64_t customdata_mask_modal; /* XXX. same as above but for temp operator use (gl renders) */
@@ -1672,8 +1704,8 @@ typedef struct Scene {
/* use preview range */
#define SCER_PRV_RANGE (1<<0)
#define SCER_LOCK_FRAME_SELECTION (1<<1)
- /* timeline/keyframe jumping - only selected items (on by default) */
-#define SCE_KEYS_NO_SELONLY (1<<2)
+ /* show/use subframes (for checking motion blur) */
+#define SCER_SHOW_SUBFRAME (1<<3)
/* mode (int now) */
#define R_OSA 0x0001
@@ -1712,7 +1744,7 @@ typedef struct Scene {
#define R_USE_WS_SHADING 0x8000000 /* use world space interpretation of lighting data */
/* seq_flag */
-#define R_SEQ_GL_PREV 1
+// #define R_SEQ_GL_PREV 1 // UNUSED, we just use setting from seq_prev_type now.
// #define R_SEQ_GL_REND 2 // UNUSED, opengl render has its own operator now.
#define R_SEQ_SOLID_TEX 4
@@ -1857,16 +1889,18 @@ extern const char *RE_engine_id_CYCLES;
/* **************** SCENE ********************* */
/* note that much higher maxframes give imprecise sub-frames, see: T46859 */
+/* Current precision is 16 for the sub-frames closer to MAXFRAME. */
+
/* for general use */
-#define MAXFRAME 500000
-#define MAXFRAMEF 500000.0f
+#define MAXFRAME 1048574
+#define MAXFRAMEF 1048574.0f
#define MINFRAME 0
#define MINFRAMEF 0.0f
/* (minimum frame number for current-frame) */
-#define MINAFRAME -500000
-#define MINAFRAMEF -500000.0f
+#define MINAFRAME -1048574
+#define MINAFRAMEF -1048574.0f
/* depricate this! */
#define TESTBASE(v3d, base) ( \
@@ -2006,6 +2040,7 @@ typedef enum eVGroupSelect {
#define SCE_DS_COLLAPSED (1<<1)
#define SCE_NLA_EDIT_ON (1<<2)
#define SCE_FRAME_DROP (1<<3)
+#define SCE_KEYS_NO_SELONLY (1<<4)
/* return flag BKE_scene_base_iter_next functions */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index e208ef39719..fd63d7c471c 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -366,7 +366,7 @@ enum {
/* uiList filter orderby type */
enum {
UILST_FLT_SORT_ALPHA = 1 << 0,
- UILST_FLT_SORT_REVERSE = 1 << 31 /* Special value, bitflag used to reverse order! */
+ UILST_FLT_SORT_REVERSE = 1u << 31 /* Special value, bitflag used to reverse order! */
};
#define UILST_FLT_SORT_MASK (((unsigned int)UILST_FLT_SORT_REVERSE) - 1)
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 1f4e4df4660..74a1a13c2eb 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -442,7 +442,7 @@ enum {
/* access scene strips directly (like a metastrip) */
SEQ_SCENE_STRIPS = (1 << 30),
- SEQ_INVALID_EFFECT = (1 << 31),
+ SEQ_INVALID_EFFECT = (1u << 31),
};
/* StripProxy->storage */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 5e015544dc9..d6490d99016 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -741,7 +741,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_ALEMBIC = (1 << 16),
FILE_TYPE_DIR = (1 << 30), /* An FS directory (i.e. S_ISDIR on its path is true). */
- FILE_TYPE_BLENDERLIB = (1 << 31),
+ FILE_TYPE_BLENDERLIB = (1u << 31),
} eFileSel_File_Types;
/* Selection Flags in filesel: struct direntry, unsigned char selflag */
@@ -1151,7 +1151,7 @@ typedef enum eSpaceNode_Flag {
SNODE_SHOW_G = (1 << 8),
SNODE_SHOW_B = (1 << 9),
SNODE_AUTO_RENDER = (1 << 5),
- SNODE_SHOW_HIGHLIGHT = (1 << 6),
+// SNODE_SHOW_HIGHLIGHT = (1 << 6), DNA_DEPRECATED
// SNODE_USE_HIDDEN_PREVIEW = (1 << 10), DNA_DEPRECATED December2013
SNODE_NEW_SHADERS = (1 << 11),
SNODE_PIN = (1 << 12),
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 0ad4482708f..cddb1e06b8c 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -48,7 +48,8 @@ struct ColorBand;
#define MAX_STYLE_NAME 64
-/* default uifont_id offered by Blender */
+/* default offered by Blender.
+ * uiFont.uifont_id */
typedef enum eUIFont_ID {
UIFONT_DEFAULT = 0,
/* UIFONT_BITMAP = 1 */ /* UNUSED */
@@ -64,7 +65,7 @@ typedef struct uiFont {
struct uiFont *next, *prev;
char filename[1024];/* 1024 = FILE_MAX */
short blf_id; /* from blfont lib */
- short uifont_id; /* own id */
+ short uifont_id; /* own id (eUIFont_ID) */
short r_to_l; /* fonts that read from left to right */
short hinting;
} uiFont;
@@ -84,7 +85,7 @@ typedef struct uiFontStyle {
float shadowcolor; /* 1 value, typically white or black anyway */
} uiFontStyle;
-/* uiFontStyle->align */
+/* uiFontStyle.align */
typedef enum eFontStyle_Align {
UI_STYLE_TEXT_LEFT = 0,
UI_STYLE_TEXT_CENTER = 1,
@@ -354,11 +355,11 @@ typedef struct ThemeWireColor {
char select[4];
char active[4];
- short flag;
+ short flag; /* eWireColor_Flags */
short pad;
} ThemeWireColor;
-/* flags for ThemeWireColor */
+/* ThemeWireColor.flag */
typedef enum eWireColor_Flags {
TH_WIRECOLOR_CONSTCOLS = (1 << 0),
TH_WIRECOLOR_TEXTCOLS = (1 << 1),
@@ -434,7 +435,8 @@ typedef struct UserDef {
/* UserDef has separate do-version handling, and can be read from other files */
int versionfile, subversionfile;
- int flag, dupflag;
+ int flag; /* eUserPref_Flag */
+ int dupflag; /* eDupli_ID_Flags */
int savetime;
char tempdir[768]; /* FILE_MAXDIR length */
char fontdir[768];
@@ -450,14 +452,15 @@ typedef struct UserDef {
int anim_player_preset;
short v2d_min_gridsize; /* minimum spacing between gridlines in View2D grids */
- short timecode_style; /* style of timecode display */
+ short timecode_style; /* eTimecodeStyles, style of timecode display */
short versions;
short dbl_click_time;
short gameflags;
short wheellinescroll;
- int uiflag, uiflag2;
+ int uiflag; /* eUserpref_UI_Flag */
+ int uiflag2; /* eUserpref_UI_Flag2 */
int language;
short userpref, viewzoom;
@@ -467,13 +470,18 @@ typedef struct UserDef {
int audioformat;
int audiochannels;
- int scrollback; /* console scrollback limit */
- int dpi; /* range 48-128? */
- char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */
+ int scrollback; /* console scrollback limit */
+ int dpi; /* range 48-128? */
+ float ui_scale; /* interface scale */
+ int ui_line_width; /* interface line width */
+ char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */
char pad2;
- short transopts;
+ short transopts; /* eUserpref_Translation_Flags */
short menuthreshold1, menuthreshold2;
-
+
+ /* startup template */
+ char app_template[64];
+
struct ListBase themes;
struct ListBase uifonts;
struct ListBase uistyles;
@@ -486,18 +494,17 @@ typedef struct UserDef {
short undosteps;
short undomemory;
short gp_manhattendist, gp_euclideandist, gp_eraser;
- short gp_settings;
+ short gp_settings; /* eGP_UserdefSettings */
short tb_leftmouse, tb_rightmouse;
struct SolidLight light[3];
short tw_hotspot, tw_flag, tw_handlesize, tw_size;
short textimeout, texcollectrate;
- short wmdrawmethod; /* removed wmpad */
+ short wmdrawmethod; /* eWM_DrawMethod */
short dragthreshold;
int memcachelimit;
int prefetchframes;
float pad_rot_angle; /* control the rotation step of the view when PAD2, PAD4, PAD6&PAD8 is use */
short frameserverport;
- short pad4;
short obcenter_dia;
short rvisize; /* rotating view icon size */
short rvibright; /* rotating view icon brightness */
@@ -505,11 +512,13 @@ typedef struct UserDef {
short smooth_viewtx; /* miliseconds to spend spinning the view */
short glreslimit;
short curssize;
- short color_picker_type;
+ short color_picker_type; /* eColorPicker_Types */
char ipo_new; /* interpolation mode for newly added F-Curves */
char keyhandles_new; /* handle types for newly added keyframes */
char gpu_select_method;
- char view_frame_type;
+ char gpu_select_pick_deph;
+ char pad4;
+ char view_frame_type; /* eZoomFrame_Mode */
int view_frame_keyframes; /* number of keyframes to zoom around current frame */
float view_frame_seconds; /* seconds to zoom around current frame */
@@ -524,15 +533,16 @@ typedef struct UserDef {
float ndof_sensitivity; /* overall sensitivity of 3D mouse */
float ndof_orbit_sensitivity;
float ndof_deadzone; /* deadzone of 3D mouse */
- int ndof_flag; /* flags for 3D mouse */
+ int ndof_flag; /* eNdof_Flag, flags for 3D mouse */
- short ogl_multisamples; /* amount of samples for OpenGL FSA, if zero no FSA */
+ short ogl_multisamples; /* eMultiSample_Type, amount of samples for OpenGL FSA, if zero no FSA */
- short image_draw_method; /* Method to be used to draw the images (AUTO, GLSL, Textures or DrawPixels) */
+ /* eImageDrawMethod, Method to be used to draw the images (AUTO, GLSL, Textures or DrawPixels) */
+ short image_draw_method;
float glalphaclip;
- short autokey_mode; /* autokeying mode */
+ short autokey_mode; /* eAutokey_Mode, autokeying mode */
short autokey_flag; /* flags for autokeying */
short text_render, pad9; /* options for text rendering */
@@ -576,7 +586,7 @@ extern UserDef U; /* from blenkernel blender.c */
/* ***************** USERDEF ****************** */
-/* userpref/section */
+/* UserDef.userpref (UI active_section) */
typedef enum eUserPref_Section {
USER_SECTION_INTERFACE = 0,
USER_SECTION_EDIT = 1,
@@ -587,19 +597,19 @@ typedef enum eUserPref_Section {
USER_SECTION_ADDONS = 6,
} eUserPref_Section;
-/* flag */
+/* UserDef.flag */
typedef enum eUserPref_Flag {
USER_AUTOSAVE = (1 << 0),
-/* USER_AUTOGRABGRID = (1 << 1), deprecated */
-/* USER_AUTOROTGRID = (1 << 2), deprecated */
-/* USER_AUTOSIZEGRID = (1 << 3), deprecated */
+ USER_FLAG_DEPRECATED_1 = (1 << 1), /* cleared */
+ USER_FLAG_DEPRECATED_2 = (1 << 2), /* cleared */
+ USER_FLAG_DEPRECATED_3 = (1 << 3), /* cleared */
USER_SCENEGLOBAL = (1 << 4),
USER_TRACKBALL = (1 << 5),
-/* USER_DUPLILINK = (1 << 6), deprecated */
-/* USER_FSCOLLUM = (1 << 7), deprecated */
+ USER_FLAG_DEPRECATED_6 = (1 << 6), /* cleared */
+ USER_FLAG_DEPRECATED_7 = (1 << 7), /* cleared */
USER_MAT_ON_OB = (1 << 8),
-/* USER_NO_CAPSLOCK = (1 << 9), */ /* not used anywhere */
-/* USER_VIEWMOVE = (1 << 10), */ /* not used anywhere */
+ USER_FLAG_DEPRECATED_9 = (1 << 9), /* cleared */
+ USER_FLAG_DEPRECATED_10 = (1 << 10), /* cleared */
USER_TOOLTIPS = (1 << 11),
USER_TWOBUTTONMOUSE = (1 << 12),
USER_NONUMPAD = (1 << 13),
@@ -618,7 +628,7 @@ typedef enum eUserPref_Flag {
USER_TOOLTIPS_PYTHON = (1 << 26),
} eUserPref_Flag;
-/* flag */
+/* bPathCompare.flag */
typedef enum ePathCompare_Flag {
USER_PATHCMP_GLOB = (1 << 0),
} ePathCompare_Flag;
@@ -629,33 +639,34 @@ typedef enum ePathCompare_Flag {
cfra = 0; \
} (void)0
-/* viewzoom */
+/* UserDef.viewzoom */
typedef enum eViewZoom_Style {
USER_ZOOM_CONT = 0,
USER_ZOOM_SCALE = 1,
USER_ZOOM_DOLLY = 2
} eViewZoom_Style;
-/* navigation_mode */
+/* UserDef.navigation_mode */
typedef enum eViewNavigation_Method {
VIEW_NAVIGATION_WALK = 0,
VIEW_NAVIGATION_FLY = 1,
} eViewNavigation_Method;
-/* flag */
+/* UserDef.flag */
typedef enum eWalkNavigation_Flag {
USER_WALK_GRAVITY = (1 << 0),
USER_WALK_MOUSE_REVERSE = (1 << 1),
} eWalkNavigation_Flag;
-/* uiflag */
+/* UserDef.uiflag */
typedef enum eUserpref_UI_Flag {
/* flags 0 and 1 were old flags (for autokeying) that aren't used anymore */
USER_WHEELZOOMDIR = (1 << 2),
USER_FILTERFILEEXTS = (1 << 3),
USER_DRAWVIEWINFO = (1 << 4),
USER_PLAINMENUS = (1 << 5),
- /* flags 6 and 7 were old flags that are no-longer used */
+ USER_LOCK_CURSOR_ADJUST = (1 << 6),
+ USER_UIFLAG_DEPRECATED_7 = (1 << 7), /* cleared */
USER_ALLWINCODECS = (1 << 8),
USER_MENUOPENAUTO = (1 << 9),
USER_ZBUF_CURSOR = (1 << 10),
@@ -679,17 +690,18 @@ typedef enum eUserpref_UI_Flag {
USER_HIDE_RECENT = (1 << 28),
USER_SHOW_THUMBNAILS = (1 << 29),
USER_QUIT_PROMPT = (1 << 30),
- USER_HIDE_SYSTEM_BOOKMARKS = (1 << 31)
+ USER_HIDE_SYSTEM_BOOKMARKS = (1u << 31)
} eUserpref_UI_Flag;
-/* uiflag2 */
+/* UserDef.uiflag2 */
typedef enum eUserpref_UI_Flag2 {
USER_KEEP_SESSION = (1 << 0),
USER_REGION_OVERLAP = (1 << 1),
USER_TRACKPAD_NATURAL = (1 << 2),
} eUserpref_UI_Flag2;
-/* Auto-Keying mode */
+/* Auto-Keying mode.
+ * UserDef.autokey_mode */
typedef enum eAutokey_Mode {
/* AUTOKEY_ON is a bitflag */
AUTOKEY_ON = 1,
@@ -699,7 +711,8 @@ typedef enum eAutokey_Mode {
AUTOKEY_MODE_EDITKEYS = 5
} eAutokey_Mode;
-/* Zoom to frame mode */
+/* Zoom to frame mode.
+ * UserDef.view_frame_type */
typedef enum eZoomFrame_Mode {
ZOOM_FRAME_MODE_KEEP_RANGE = 0,
ZOOM_FRAME_MODE_SECONDS = 1,
@@ -722,20 +735,20 @@ typedef enum eAutokey_Flag {
ANIMRECORD_FLAG_WITHNLA = (1 << 10),
} eAutokey_Flag;
-/* transopts */
+/* UserDef.transopts */
typedef enum eUserpref_Translation_Flags {
USER_TR_TOOLTIPS = (1 << 0),
USER_TR_IFACE = (1 << 1),
-/* USER_TR_MENUS = (1 << 2), deprecated */
-/* USER_TR_FILESELECT = (1 << 3), deprecated */
-/* USER_TR_TEXTEDIT = (1 << 4), deprecated */
+ USER_TR_DEPRECATED_2 = (1 << 2), /* cleared */
+ USER_TR_DEPRECATED_3 = (1 << 3), /* cleared */
+ USER_TR_DEPRECATED_4 = (1 << 4), /* cleared */
USER_DOTRANSLATE = (1 << 5),
- USER_USETEXTUREFONT = (1 << 6),
-/* CONVERT_TO_UTF8 = (1 << 7), deprecated */
+ USER_TR_DEPRECATED_6 = (1 << 6), /* cleared */
+ USER_TR_DEPRECATED_7 = (1 << 7), /* cleared */
USER_TR_NEWDATANAME = (1 << 8),
} eUserpref_Translation_Flags;
-/* dupflag */
+/* UserDef.dupflag */
typedef enum eDupli_ID_Flags {
USER_DUP_MESH = (1 << 0),
USER_DUP_CURVE = (1 << 1),
@@ -751,14 +764,13 @@ typedef enum eDupli_ID_Flags {
USER_DUP_PSYS = (1 << 11)
} eDupli_ID_Flags;
-/* gameflags */
+/* UserDef.gameflags */
typedef enum eOpenGL_RenderingOptions {
- /* USER_DEPRECATED_FLAG = (1 << 0), */
- /* USER_DISABLE_SOUND = (1 << 1), */ /* deprecated, don't use without checking for */
- /* backwards compatibilty in do_versions! */
- USER_DISABLE_MIPMAP = (1 << 2),
- /* USER_DISABLE_VBO = (1 << 3), */ /* DEPRECATED we always use vertex buffers now */
- /* USER_DISABLE_AA = (1 << 4), */ /* DEPRECATED */
+ USER_GL_RENDER_DEPRECATED_0 = (1 << 0),
+ USER_GL_RENDER_DEPRECATED_1 = (1 << 1),
+ USER_DISABLE_MIPMAP = (1 << 2),
+ USER_GL_RENDER_DEPRECATED_3 = (1 << 3),
+ USER_GL_RENDER_DEPRECATED_4 = (1 << 4),
} eOpenGL_RenderingOptions;
/* selection method for opengl gpu_select_method */
@@ -768,7 +780,8 @@ typedef enum eOpenGL_SelectOptions {
USER_SELECT_USE_SELECT_RENDERMODE = 2
} eOpenGL_SelectOptions;
-/* wm draw method */
+/* wm draw method.
+ * UserDef.wmdrawmethod */
typedef enum eWM_DrawMethod {
USER_DRAW_TRIPLE = 0,
USER_DRAW_OVERLAP = 1,
@@ -777,20 +790,23 @@ typedef enum eWM_DrawMethod {
USER_DRAW_OVERLAP_FLIP = 4,
} eWM_DrawMethod;
-/* text draw options */
+/* text draw options
+ * UserDef.text_render */
typedef enum eText_Draw_Options {
USER_TEXT_DISABLE_AA = (1 << 0),
} eText_Draw_Options;
/* tw_flag (transform widget) */
-/* gp_settings (Grease Pencil Settings) */
+/* Grease Pencil Settings.
+ * UserDef.gp_settings */
typedef enum eGP_UserdefSettings {
GP_PAINT_DOSMOOTH = (1 << 0),
GP_PAINT_DOSIMPLIFY = (1 << 1),
} eGP_UserdefSettings;
-/* color picker types */
+/* Color Picker Types.
+ * UserDef.color_picker_type */
typedef enum eColorPicker_Types {
USER_CP_CIRCLE_HSV = 0,
USER_CP_SQUARE_SV = 1,
@@ -799,7 +815,8 @@ typedef enum eColorPicker_Types {
USER_CP_CIRCLE_HSL = 4,
} eColorPicker_Types;
-/* timecode display styles */
+/* timecode display styles
+ * UserDef.timecode_style */
typedef enum eTimecodeStyles {
/* as little info as is necessary to show relevant info
* with '+' to denote the frames
@@ -834,7 +851,7 @@ typedef enum eTheme_DrawTypes {
TH_SHADED = 4
} eTheme_DrawTypes;
-/* ndof_flag (3D mouse options) */
+/* UserDef.ndof_flag (3D mouse options) */
typedef enum eNdof_Flag {
NDOF_SHOW_GUIDE = (1 << 0),
NDOF_FLY_HELICOPTER = (1 << 1),
@@ -867,6 +884,7 @@ typedef enum eNdof_Flag {
#define NDOF_PIXELS_PER_SECOND 600.0f
+/* UserDef.ogl_multisamples */
typedef enum eMultiSample_Type {
USER_MULTISAMPLE_NONE = 0,
USER_MULTISAMPLE_2 = 2,
@@ -874,7 +892,8 @@ typedef enum eMultiSample_Type {
USER_MULTISAMPLE_8 = 8,
USER_MULTISAMPLE_16 = 16,
} eMultiSample_Type;
-
+
+/* UserDef.image_draw_method */
typedef enum eImageDrawMethod {
/* IMAGE_DRAW_METHOD_AUTO = 0, */ /* Currently unused */
IMAGE_DRAW_METHOD_GLSL = 1,
@@ -882,6 +901,7 @@ typedef enum eImageDrawMethod {
IMAGE_DRAW_METHOD_DRAWPIXELS = 3,
} eImageDrawMethod;
+/* UserDef.virtual_pixel */
typedef enum eUserpref_VirtualPixel {
VIRTUAL_PIXEL_NATIVE = 0,
VIRTUAL_PIXEL_DOUBLE = 1,
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 4c243507e82..b9894d46b5b 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -225,7 +225,8 @@ typedef struct View3D {
struct GPUFXSettings fx_settings;
void *properties_storage; /* Nkey panel stores stuff here (runtime only!) */
- struct Material *defmaterial; /* used by matcap now */
+ /* Allocated per view, not library data (used by matcap). */
+ struct Material *defmaterial;
/* XXX deprecated? */
struct bGPdata *gpd DNA_DEPRECATED; /* Grease-Pencil Data (annotation layers) */
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 96085a79eff..181d01e04fc 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -169,7 +169,7 @@ void DNA_sdna_free(SDNA *sdna)
}
MEM_freeN((void *)sdna->names);
- MEM_freeN(sdna->types);
+ MEM_freeN((void *)sdna->types);
MEM_freeN(sdna->structs);
#ifdef WITH_DNA_GHASH
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 44d1a6bfaaf..178d2d398e9 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -262,6 +262,7 @@ extern StructRNA RNA_GPencilLayer;
extern StructRNA RNA_GPencilPalette;
extern StructRNA RNA_GPencilPaletteColor;
extern StructRNA RNA_GPencilBrush;
+extern StructRNA RNA_GPencilInterpolateSettings;
extern StructRNA RNA_GPencilStroke;
extern StructRNA RNA_GPencilStrokePoint;
extern StructRNA RNA_GPencilSculptSettings;
@@ -487,7 +488,6 @@ extern StructRNA RNA_PropertyGroupItem;
extern StructRNA RNA_PropertySensor;
extern StructRNA RNA_PythonConstraint;
extern StructRNA RNA_PythonController;
-extern StructRNA RNA_QuickTimeSettings;
extern StructRNA RNA_RadarSensor;
extern StructRNA RNA_RandomSensor;
extern StructRNA RNA_RaySensor;
@@ -597,6 +597,7 @@ extern StructRNA RNA_StucciTexture;
extern StructRNA RNA_SubsurfModifier;
extern StructRNA RNA_SunLamp;
extern StructRNA RNA_SurfaceCurve;
+extern StructRNA RNA_SurfaceDeformModifier;
extern StructRNA RNA_SurfaceModifier;
extern StructRNA RNA_TexMapping;
extern StructRNA RNA_Text;
@@ -765,6 +766,8 @@ void RNA_struct_blender_type_set(StructRNA *srna, void *blender_type);
struct IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create);
bool RNA_struct_idprops_check(StructRNA *srna);
bool RNA_struct_idprops_register_check(const StructRNA *type);
+bool RNA_struct_idprops_datablock_allowed(const StructRNA *type);
+bool RNA_struct_idprops_contains_datablock(const StructRNA *type);
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier);
PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier);
@@ -779,6 +782,9 @@ const struct ListBase *RNA_struct_type_functions(StructRNA *srna);
char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len);
+bool RNA_struct_available_or_report(struct ReportList *reports, const char *identifier);
+bool RNA_struct_bl_idname_ok_or_report(struct ReportList *reports, const char *identifier, const char *sep);
+
/* Properties
*
* Access to struct properties. All this works with RNA pointers rather than
@@ -793,6 +799,7 @@ PropertyType RNA_property_type(PropertyRNA *prop);
PropertySubType RNA_property_subtype(PropertyRNA *prop);
PropertyUnit RNA_property_unit(PropertyRNA *prop);
int RNA_property_flag(PropertyRNA *prop);
+bool RNA_property_builtin(PropertyRNA *prop);
void *RNA_property_py_data_get(PropertyRNA *prop);
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop);
@@ -1142,6 +1149,8 @@ const struct ListBase *RNA_function_defined_parameters(FunctionRNA *func);
/* Utility */
+int RNA_parameter_flag(PropertyRNA *prop);
+
ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *ptr, FunctionRNA *func);
void RNA_parameter_list_free(ParameterList *parms);
int RNA_parameter_list_size(ParameterList *parms);
@@ -1190,7 +1199,7 @@ StructRNA *ID_code_to_RNA_type(short idcode);
} (void)0
/* macro which inserts the function name */
-#if defined __GNUC__ || defined __sun
+#if defined __GNUC__
# define RNA_warning(format, args ...) _RNA_warning("%s: " format "\n", __func__, ##args)
#else
# define RNA_warning(format, ...) _RNA_warning("%s: " format "\n", __FUNCTION__, __VA_ARGS__)
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index bf8ea048fae..42ffe774720 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -62,7 +62,8 @@ void RNA_def_struct_refine_func(StructRNA *srna, const char *refine);
void RNA_def_struct_idprops_func(StructRNA *srna, const char *refine);
void RNA_def_struct_register_funcs(StructRNA *srna, const char *reg, const char *unreg, const char *instance);
void RNA_def_struct_path_func(StructRNA *srna, const char *path);
-void RNA_def_struct_identifier(StructRNA *srna, const char *identifier);
+void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier);
+void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier);
void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description);
void RNA_def_struct_ui_icon(StructRNA *srna, int icon);
void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *ext);
@@ -137,8 +138,8 @@ void RNA_def_property_enum_bitflag_sdna(PropertyRNA *prop, const char *structnam
void RNA_def_property_pointer_sdna(PropertyRNA *prop, const char *structname, const char *propname);
void RNA_def_property_collection_sdna(PropertyRNA *prop, const char *structname, const char *propname, const char *lengthpropname);
-void RNA_def_property_flag(PropertyRNA *prop, int flag);
-void RNA_def_property_clear_flag(PropertyRNA *prop, int flag);
+void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag);
+void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag);
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype);
void RNA_def_property_array(PropertyRNA *prop, int length);
void RNA_def_property_multi_array(PropertyRNA *prop, int dimension, const int length[]);
@@ -167,6 +168,7 @@ void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable);
void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable);
void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func);
+void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func);
void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength);
void RNA_def_property_boolean_funcs(PropertyRNA *prop, const char *get, const char *set);
@@ -201,6 +203,9 @@ void RNA_def_function_output(FunctionRNA *func, PropertyRNA *ret);
void RNA_def_function_flag(FunctionRNA *func, int flag);
void RNA_def_function_ui_description(FunctionRNA *func, const char *description);
+void RNA_def_parameter_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter);
+void RNA_def_parameter_clear_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter);
+
/* Dynamic Enums
* strings are not freed, assumed pointing to static location. */
@@ -212,8 +217,8 @@ void RNA_enum_item_end(EnumPropertyItem **items, int *totitem);
/* Memory management */
-void RNA_def_struct_duplicate_pointers(StructRNA *srna);
-void RNA_def_struct_free_pointers(StructRNA *srna);
+void RNA_def_struct_duplicate_pointers(BlenderRNA *brna, StructRNA *srna);
+void RNA_def_struct_free_pointers(BlenderRNA *brna, StructRNA *srna);
void RNA_def_func_duplicate_pointers(FunctionRNA *func);
void RNA_def_func_free_pointers(FunctionRNA *func);
void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA *prop);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 1c9b3593d17..f8e240d57bf 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -114,6 +114,8 @@ extern EnumPropertyItem rna_enum_brush_image_tool_items[];
extern EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[];
+extern EnumPropertyItem rna_enum_uv_sculpt_tool_items[];
+
extern EnumPropertyItem rna_enum_axis_xy_items[];
extern EnumPropertyItem rna_enum_axis_xyz_items[];
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 276531992f9..e119c49401e 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -155,7 +155,8 @@ typedef enum PropertySubType {
} PropertySubType;
/* Make sure enums are updated with these */
-/* HIGHEST FLAG IN USE: 1 << 31 */
+/* HIGHEST FLAG IN USE: 1 << 31
+ * FREE FLAGS: 2, 3, 7, 9, 11, 13, 14, 15, 30 */
typedef enum PropertyFlag {
/* editable means the property is editable in the user
* interface, properties are editable by default except
@@ -173,9 +174,11 @@ typedef enum PropertyFlag {
* and collections */
PROP_ANIMATABLE = (1 << 1),
- /* This flag means when the property's widget is in 'textedit' mode, it will be updated after every typed char,
- * instead of waiting final validation. Used e.g. for text searchbox. */
- PROP_TEXTEDIT_UPDATE = (1 << 31),
+ /* This flag means when the property's widget is in 'textedit' mode, it will be updated
+ * after every typed char, instead of waiting final validation. Used e.g. for text searchbox.
+ * It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag
+ * for search/filter properties, but this works just fine for now. */
+ PROP_TEXTEDIT_UPDATE = (1u << 31),
/* icon */
PROP_ICONS_CONSECUTIVE = (1 << 12),
@@ -185,20 +188,6 @@ typedef enum PropertyFlag {
/* do not write in presets */
PROP_SKIP_SAVE = (1 << 28),
- /* function parameter flags */
- PROP_REQUIRED = (1 << 2),
- PROP_OUTPUT = (1 << 3),
- PROP_RNAPTR = (1 << 11),
- /* This allows for non-breaking API updates, when adding non-critical new parameter to a callback function.
- * This way, old py code defining funcs without that parameter would still work.
- * WARNING: any parameter after the first PYFUNC_OPTIONAL one will be considered as optional!
- * NOTE: only for input parameters!
- */
- PROP_PYFUNC_OPTIONAL = (1 << 30),
- /* registering */
- PROP_REGISTER = (1 << 4),
- PROP_REGISTER_OPTIONAL = PROP_REGISTER | (1 << 5),
-
/* numbers */
/* each value is related proportionally (object scale, image size) */
@@ -229,25 +218,37 @@ typedef enum PropertyFlag {
/* need context for update function */
PROP_CONTEXT_UPDATE = (1 << 22),
- PROP_CONTEXT_PROPERTY_UPDATE = (1 << 22) | (1 << 27),
+ PROP_CONTEXT_PROPERTY_UPDATE = PROP_CONTEXT_UPDATE | (1 << 27),
+
+ /* registering */
+ PROP_REGISTER = (1 << 4),
+ PROP_REGISTER_OPTIONAL = PROP_REGISTER | (1 << 5),
/* Use for arrays or for any data that should not have a reference kept
* most common case is functions that return arrays where the array */
PROP_THICK_WRAP = (1 << 23),
- /* internal flags */
- PROP_BUILTIN = (1 << 7),
- PROP_EXPORT = (1 << 8),
- PROP_RUNTIME = (1 << 9),
- PROP_IDPROPERTY = (1 << 10),
- PROP_RAW_ACCESS = (1 << 13),
- PROP_RAW_ARRAY = (1 << 14),
- PROP_FREE_POINTERS = (1 << 15),
+ PROP_EXPORT = (1 << 8), /* XXX Is this still used? makesrna.c seems to ignore it currently... */
+ PROP_IDPROPERTY = (1 << 10), /* This is an IDProperty, not a DNA one. */
PROP_DYNAMIC = (1 << 17), /* for dynamic arrays, and retvals of type string */
PROP_ENUM_NO_CONTEXT = (1 << 24), /* for enum that shouldn't be contextual */
PROP_ENUM_NO_TRANSLATE = (1 << 29), /* for enums not to be translated (e.g. renderlayers' names in nodes) */
} PropertyFlag;
+/* Function parameters flags.
+ * WARNING: 16bits only. */
+typedef enum ParameterFlag {
+ PARM_REQUIRED = (1 << 0),
+ PARM_OUTPUT = (1 << 1),
+ PARM_RNAPTR = (1 << 2),
+ /* This allows for non-breaking API updates, when adding non-critical new parameter to a callback function.
+ * This way, old py code defining funcs without that parameter would still work.
+ * WARNING: any parameter after the first PYFUNC_OPTIONAL one will be considered as optional!
+ * NOTE: only for input parameters!
+ */
+ PARM_PYFUNC_OPTIONAL = (1 << 3),
+} ParameterFlag;
+
struct CollectionPropertyIterator;
struct Link;
typedef int (*IteratorSkipFunc)(struct CollectionPropertyIterator *iter, void *data);
@@ -433,6 +434,10 @@ typedef enum StructFlag {
STRUCT_GENERATED = (1 << 4),
STRUCT_FREE_POINTERS = (1 << 5),
STRUCT_NO_IDPROPERTIES = (1 << 6), /* Menus and Panels don't need properties */
+ STRUCT_NO_DATABLOCK_IDPROPERTIES = (1 << 7), /* e.g. for Operator */
+ STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES = (1 << 8), /* for PropertyGroup which contains pointers to datablocks */
+ STRUCT_PUBLIC_NAMESPACE = (1 << 9), /* Added to type-map #BlenderRNA.structs_map */
+ STRUCT_PUBLIC_NAMESPACE_INHERIT = (1 << 10), /* All subtypes are added too. */
} StructFlag;
typedef int (*StructValidateFunc)(struct PointerRNA *ptr, void *data, int *have_function);
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 0f3ea27a7f9..743d192f0c5 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -140,6 +140,9 @@ set(GENSRC_CFLAGS)
if(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
set(GENSRC_CFLAGS "-Wno-missing-prototypes")
endif()
+if(CMAKE_C_COMPILER_ID MATCHES "Clang")
+ set(GENSRC_CFLAGS "${GENSRC_CFLAGS} -Wno-missing-variable-declarations")
+endif()
if(GENSRC_CFLAGS)
set_source_files_properties(${GENSRC} PROPERTIES COMPILE_FLAGS "${GENSRC_CFLAGS}")
@@ -176,9 +179,6 @@ set(INC_SYS
if(WITH_CYCLES)
add_definitions(-DWITH_CYCLES)
- if(WITH_CYCLES_DEBUG)
- add_definitions(-DWITH_CYCLES_DEBUG)
- endif()
endif()
if(WITH_PYTHON)
@@ -232,13 +232,6 @@ if(WITH_AUDASPACE)
)
endif()
-if(WITH_CODEC_QUICKTIME)
- list(APPEND INC
- ../../quicktime
- )
- add_definitions(-DWITH_QUICKTIME)
-endif()
-
if(WITH_CODEC_FFMPEG)
list(APPEND INC
../../../../intern/ffmpeg
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 77b000beed8..6c285e57fc3 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -463,7 +463,7 @@ static const char *rna_parameter_type_name(PropertyRNA *parm)
{
PointerPropertyRNA *pparm = (PointerPropertyRNA *)parm;
- if (parm->flag & PROP_RNAPTR)
+ if (parm->flag_parameter & PARM_RNAPTR)
return "PointerRNA";
else
return rna_find_dna_type((const char *)pparm->type);
@@ -507,7 +507,7 @@ static void rna_float_print(FILE *f, float num)
{
if (num == -FLT_MAX) fprintf(f, "-FLT_MAX");
else if (num == FLT_MAX) fprintf(f, "FLT_MAX");
- else if ((int64_t)num == num) fprintf(f, "%.1ff", num);
+ else if ((ABS(num) < INT64_MAX) && ((int64_t)num == num)) fprintf(f, "%.1ff", num);
else fprintf(f, "%.10ff", num);
}
@@ -1409,23 +1409,23 @@ static void rna_set_raw_property(PropertyDefRNA *dp, PropertyRNA *prop)
if (STREQ(dp->dnatype, "char")) {
prop->rawtype = PROP_RAW_CHAR;
- prop->flag |= PROP_RAW_ACCESS;
+ prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "short")) {
prop->rawtype = PROP_RAW_SHORT;
- prop->flag |= PROP_RAW_ACCESS;
+ prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "int")) {
prop->rawtype = PROP_RAW_INT;
- prop->flag |= PROP_RAW_ACCESS;
+ prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "float")) {
prop->rawtype = PROP_RAW_FLOAT;
- prop->flag |= PROP_RAW_ACCESS;
+ prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "double")) {
prop->rawtype = PROP_RAW_DOUBLE;
- prop->flag |= PROP_RAW_ACCESS;
+ prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
}
@@ -1553,7 +1553,7 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
if (STREQ((const char *)cprop->next, "rna_iterator_array_next") &&
STREQ((const char *)cprop->get, "rna_iterator_array_get"))
{
- prop->flag |= PROP_RAW_ARRAY;
+ prop->flag_internal |= PROP_INTERN_RAW_ARRAY;
}
cprop->get = (void *)rna_def_property_get_func(f, srna, prop, dp, (const char *)cprop->get);
@@ -1599,8 +1599,9 @@ static void rna_def_property_funcs_header(FILE *f, StructRNA *srna, PropertyDefR
prop = dp->prop;
- if (prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN))
+ if (prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN) {
return;
+ }
func = rna_alloc_function_name(srna->identifier, rna_safe_id(prop->identifier), "");
@@ -1719,8 +1720,9 @@ static void rna_def_property_funcs_header_cpp(FILE *f, StructRNA *srna, Property
prop = dp->prop;
- if (prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN))
+ if (prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN) {
return;
+ }
/* disabled for now to avoid msvc compiler error due to large file size */
#if 0
@@ -1822,8 +1824,9 @@ static void rna_def_property_funcs_header_cpp(FILE *f, StructRNA *srna, Property
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)dp->prop;
const char *collection_funcs = "DefaultCollectionFunctions";
- if (!(dp->prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)) && cprop->property.srna)
+ if (!(dp->prop->flag & PROP_IDPROPERTY || dp->prop->flag_internal & PROP_INTERN_BUILTIN) && cprop->property.srna) {
collection_funcs = (char *)cprop->property.srna;
+ }
if (cprop->item_type)
fprintf(f, "\tCOLLECTION_PROPERTY(%s, %s, %s, %s, %s, %s, %s)", collection_funcs, (const char *)cprop->item_type, srna->identifier,
@@ -1879,7 +1882,7 @@ static void rna_def_struct_function_prototype_cpp(FILE *f, StructRNA *UNUSED(srn
WRITE_PARAM("Context C");
for (dp = dfunc->cont.properties.first; dp; dp = dp->next) {
- int type, flag, pout;
+ int type, flag, flag_parameter, pout;
const char *ptrstr;
if (dp->prop == func->c_ret)
@@ -1887,7 +1890,8 @@ static void rna_def_struct_function_prototype_cpp(FILE *f, StructRNA *UNUSED(srn
type = dp->prop->type;
flag = dp->prop->flag;
- pout = (flag & PROP_OUTPUT);
+ flag_parameter = dp->prop->flag_parameter;
+ pout = (flag_parameter & PARM_OUTPUT);
if (flag & PROP_DYNAMIC)
ptrstr = pout ? "**" : "*";
@@ -1903,7 +1907,7 @@ static void rna_def_struct_function_prototype_cpp(FILE *f, StructRNA *UNUSED(srn
WRITE_COMMA;
if (flag & PROP_DYNAMIC)
- fprintf(f, "int %s%s_len, ", (flag & PROP_OUTPUT) ? "*" : "", dp->prop->identifier);
+ fprintf(f, "int %s%s_len, ", (flag_parameter & PARM_OUTPUT) ? "*" : "", dp->prop->identifier);
if (!(flag & PROP_DYNAMIC) && dp->prop->arraydimension)
fprintf(f, "%s %s[%u]", rna_parameter_type_cpp_name(dp->prop),
@@ -1941,8 +1945,9 @@ static void rna_def_property_funcs_impl_cpp(FILE *f, StructRNA *srna, PropertyDe
prop = dp->prop;
- if (prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN))
+ if (prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN) {
return;
+ }
switch (prop->type) {
case PROP_BOOLEAN:
@@ -2075,9 +2080,9 @@ static void rna_def_struct_function_call_impl_cpp(FILE *f, StructRNA *srna, Func
fprintf(f, "%s_len, ", dp->prop->identifier);
if (dp->prop->type == PROP_POINTER)
- if ((dp->prop->flag & PROP_RNAPTR) && !(dp->prop->flag & PROP_THICK_WRAP))
+ if ((dp->prop->flag_parameter & PARM_RNAPTR) && !(dp->prop->flag & PROP_THICK_WRAP))
fprintf(f, "(::%s *) &%s.ptr", rna_parameter_type_name(dp->prop), rna_safe_id(dp->prop->identifier));
- else if (dp->prop->flag & PROP_OUTPUT)
+ else if (dp->prop->flag_parameter & PARM_OUTPUT)
fprintf(f, "(::%s **) &%s->ptr.data", rna_parameter_type_name(dp->prop), rna_safe_id(dp->prop->identifier));
else
fprintf(f, "(::%s *) %s.ptr.data", rna_parameter_type_name(dp->prop), rna_safe_id(dp->prop->identifier));
@@ -2110,7 +2115,7 @@ static void rna_def_struct_function_impl_cpp(FILE *f, StructRNA *srna, FunctionD
fprintf(f, "\t\tPointerRNA result;\n");
- if ((dp->prop->flag & PROP_RNAPTR) == 0) {
+ if ((dp->prop->flag_parameter & PARM_RNAPTR) == 0) {
StructRNA *ret_srna = rna_find_struct((const char *) pprop->type);
fprintf(f, "\t\t::%s *retdata = ", rna_parameter_type_name(dp->prop));
rna_def_struct_function_call_impl_cpp(f, srna, dfunc);
@@ -2221,7 +2226,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
const char *funcname, *valstr;
const char *ptrstr;
const bool has_data = (dfunc->cont.properties.first != NULL);
- int flag, pout, cptr, first;
+ int flag, flag_parameter, pout, cptr, first;
srna = dsrna->srna;
func = dfunc->func;
@@ -2254,8 +2259,9 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
for (; dparm; dparm = dparm->next) {
type = dparm->prop->type;
flag = dparm->prop->flag;
- pout = (flag & PROP_OUTPUT);
- cptr = ((type == PROP_POINTER) && !(flag & PROP_RNAPTR));
+ flag_parameter = dparm->prop->flag_parameter;
+ pout = (flag_parameter & PARM_OUTPUT);
+ cptr = ((type == PROP_POINTER) && !(flag_parameter & PARM_RNAPTR));
if (dparm->prop == func->c_ret)
ptrstr = cptr || dparm->prop->arraydimension ? "*" : "";
@@ -2265,7 +2271,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
/* fixed size arrays and RNA pointers are pre-allocated on the ParameterList stack, pass a pointer to it */
else if (type == PROP_POINTER || dparm->prop->arraydimension)
ptrstr = "*";
- else if ((type == PROP_POINTER) && (flag & PROP_RNAPTR) && !(flag & PROP_THICK_WRAP))
+ else if ((type == PROP_POINTER) && (flag_parameter & PARM_RNAPTR) && !(flag & PROP_THICK_WRAP))
ptrstr = "*";
/* PROP_THICK_WRAP strings are pre-allocated on the ParameterList stack,
* but type name for string props is already (char *), so leave empty */
@@ -2311,8 +2317,9 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
for (; dparm; dparm = dparm->next) {
type = dparm->prop->type;
flag = dparm->prop->flag;
- pout = (flag & PROP_OUTPUT);
- cptr = ((type == PROP_POINTER) && !(flag & PROP_RNAPTR));
+ flag_parameter = dparm->prop->flag_parameter;
+ pout = (flag_parameter & PARM_OUTPUT);
+ cptr = ((type == PROP_POINTER) && !(flag_parameter & PARM_RNAPTR));
if (dparm->prop == func->c_ret)
fprintf(f, "\t_retdata = _data;\n");
@@ -2422,7 +2429,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
if (func->c_ret) {
dparm = rna_find_parameter_def(func->c_ret);
- ptrstr = (((dparm->prop->type == PROP_POINTER) && !(dparm->prop->flag & PROP_RNAPTR)) ||
+ ptrstr = (((dparm->prop->type == PROP_POINTER) && !(dparm->prop->flag_parameter & PARM_RNAPTR)) ||
(dparm->prop->arraydimension)) ? "*" : "";
fprintf(f, "\t*((%s%s %s*)_retdata) = %s;\n", rna_type_struct(dparm->prop),
rna_parameter_type_name(dparm->prop), ptrstr, func->c_ret->identifier);
@@ -2576,17 +2583,23 @@ static void rna_generate_blender(BlenderRNA *brna, FILE *f)
{
StructRNA *srna;
- fprintf(f, "BlenderRNA BLENDER_RNA = {");
-
+ fprintf(f,
+ "BlenderRNA BLENDER_RNA = {\n"
+ "\t.structs = {"
+ );
srna = brna->structs.first;
- if (srna) fprintf(f, "{&RNA_%s, ", srna->identifier);
- else fprintf(f, "{NULL, ");
+ if (srna) fprintf(f, "&RNA_%s, ", srna->identifier);
+ else fprintf(f, "NULL, ");
srna = brna->structs.last;
- if (srna) fprintf(f, "&RNA_%s}", srna->identifier);
- else fprintf(f, "NULL}");
+ if (srna) fprintf(f, "&RNA_%s},\n", srna->identifier);
+ else fprintf(f, "NULL},\n");
- fprintf(f, "};\n\n");
+ fprintf(f,
+ "\t.structs_map = NULL,\n"
+ "\t.structs_len = 0,\n"
+ "};\n\n"
+ );
}
static void rna_generate_property_prototypes(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE *f)
@@ -2657,7 +2670,7 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F
PropertyDefRNA *dparm;
StructDefRNA *dsrna;
PropertyType type;
- int flag, pout, cptr, first;
+ int flag, flag_parameter, pout, cptr, first;
const char *ptrstr;
dsrna = rna_find_struct_def(srna);
@@ -2668,7 +2681,7 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F
if (dparm->prop == func->c_ret) {
if (dparm->prop->arraydimension)
fprintf(f, "XXX no array return types yet"); /* XXX not supported */
- else if (dparm->prop->type == PROP_POINTER && !(dparm->prop->flag & PROP_RNAPTR))
+ else if (dparm->prop->type == PROP_POINTER && !(dparm->prop->flag_parameter & PARM_RNAPTR))
fprintf(f, "%s%s *", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop));
else
fprintf(f, "%s%s ", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop));
@@ -2730,8 +2743,9 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F
for (dparm = dfunc->cont.properties.first; dparm; dparm = dparm->next) {
type = dparm->prop->type;
flag = dparm->prop->flag;
- pout = (flag & PROP_OUTPUT);
- cptr = ((type == PROP_POINTER) && !(flag & PROP_RNAPTR));
+ flag_parameter = dparm->prop->flag_parameter;
+ pout = (flag_parameter & PARM_OUTPUT);
+ cptr = ((type == PROP_POINTER) && !(flag_parameter & PARM_RNAPTR));
if (dparm->prop == func->c_ret)
continue;
@@ -2986,7 +3000,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
else fprintf(f, "NULL,\n");
fprintf(f, "\t%d, ", prop->magic);
rna_print_c_string(f, prop->identifier);
- fprintf(f, ", %d, ", prop->flag);
+ fprintf(f, ", %d, %d, %d, ", prop->flag, prop->flag_parameter, prop->flag_internal);
rna_print_c_string(f, prop->name); fprintf(f, ",\n\t");
rna_print_c_string(f, prop->description); fprintf(f, ",\n\t");
fprintf(f, "%d, ", prop->icon);
@@ -3008,7 +3022,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
rna_function_string(prop->editable),
rna_function_string(prop->itemeditable));
- if (prop->flag & PROP_RAW_ACCESS) rna_set_raw_offset(f, srna, prop);
+ if (prop->flag_internal & PROP_INTERN_RAW_ACCESS) rna_set_raw_offset(f, srna, prop);
else fprintf(f, "\t0, -1");
/* our own type - collections/arrays only */
@@ -3739,7 +3753,7 @@ static const char *cpp_classes = ""
"template<typename T, TBeginFunc Tbegin, TNextFunc Tnext, TEndFunc Tend>\n"
"class CollectionIterator {\n"
"public:\n"
-" CollectionIterator() : t(iter.ptr), init(false) { iter.valid = false; }\n"
+" CollectionIterator() : iter(), t(iter.ptr), init(false) { iter.valid = false; }\n"
" ~CollectionIterator(void) { if (init) Tend(&iter); };\n"
"\n"
" operator bool(void)\n"
@@ -3758,7 +3772,7 @@ static const char *cpp_classes = ""
"\n"
"private:\n"
" const CollectionIterator<T, Tbegin, Tnext, Tend>& operator = "
-"(const CollectionIterator<T, Tbegin, Tnext, Tend>& copy) {}\n"
+"(const CollectionIterator<T, Tbegin, Tnext, Tend>& /*copy*/) {}\n"
""
" CollectionPropertyIterator iter;\n"
" T t;\n"
@@ -3797,9 +3811,11 @@ static const char *cpp_classes = ""
static int rna_is_collection_prop(PropertyRNA *prop)
{
- if (!(prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)))
- if (prop->type == PROP_COLLECTION)
+ if (!(prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN)) {
+ if (prop->type == PROP_COLLECTION) {
return 1;
+ }
+ }
return 0;
}
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 87fb45a4419..bf767d47994 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -250,9 +250,10 @@ void rna_PropertyGroup_unregister(Main *UNUSED(bmain), StructRNA *type)
RNA_struct_free(&BLENDER_RNA, type);
}
-StructRNA *rna_PropertyGroup_register(Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc UNUSED(call),
- StructFreeFunc UNUSED(free))
+StructRNA *rna_PropertyGroup_register(
+ Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc UNUSED(call),
+ StructFreeFunc UNUSED(free))
{
PointerRNA dummyptr;
@@ -342,7 +343,7 @@ static void rna_ID_user_clear(ID *id)
static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
{
- if (GS(id->name) == GS(new_id->name)) {
+ if ((GS(id->name) == GS(new_id->name)) && (id != new_id)) {
/* 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);
}
@@ -358,7 +359,9 @@ static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int clear_prox
id_make_local(bmain, self, false, false);
}
- return self->newid ? self->newid : self;
+ ID *ret_id = self->newid ? self->newid : self;
+ BKE_id_clear_newpoin(self);
+ return ret_id;
}
@@ -800,7 +803,11 @@ static void rna_def_ID_properties(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
#endif
- /* IDP_ID -- not implemented yet in id properties */
+ /* IDP_ID */
+ prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY | PROP_NEVER_UNLINK);
+ RNA_def_property_struct_type(prop, "ID");
+
/* ID property groups > level 0, since level 0 group is merged
* with native RNA properties. the builtin_properties will take
@@ -838,7 +845,7 @@ static void rna_def_ID_materials(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Add a new material to the data-block");
parm = RNA_def_pointer(func, "material", "Material", "", "Material to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "pop", "rna_IDMaterials_pop_id");
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
@@ -1012,7 +1019,7 @@ static void rna_def_ID(BlenderRNA *brna)
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_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
func = RNA_def_function(srna, "make_local", "rna_ID_make_local");
RNA_def_function_ui_description(func, "Make this datablock local, return local one "
@@ -1021,14 +1028,13 @@ static void rna_def_ID(BlenderRNA *brna)
parm = RNA_def_boolean(func, "clear_proxy", true, "",
"Whether to clear proxies (the default behavior, "
"note that if object has to be duplicated to be made local, proxies are always cleared)");
- RNA_def_property_flag(parm, PROP_PYFUNC_OPTIONAL);
parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied");
RNA_def_function_return(func, parm);
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");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_int(func, "count", 0, 0, INT_MAX,
"", "Number of usages/references of given id by current data-block", 0, INT_MAX);
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 6f054e586ec..bfa1e7cef93 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -50,6 +50,7 @@
#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_fcurve.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -75,14 +76,22 @@ void RNA_init(void)
StructRNA *srna;
PropertyRNA *prop;
+ BLENDER_RNA.structs_map = BLI_ghash_str_new_ex(__func__, 2048);
+ BLENDER_RNA.structs_len = 0;
+
for (srna = BLENDER_RNA.structs.first; srna; srna = srna->cont.next) {
if (!srna->cont.prophash) {
srna->cont.prophash = BLI_ghash_str_new("RNA_init gh");
- for (prop = srna->cont.properties.first; prop; prop = prop->next)
- if (!(prop->flag & PROP_BUILTIN))
+ for (prop = srna->cont.properties.first; prop; prop = prop->next) {
+ if (!(prop->flag_internal & PROP_INTERN_BUILTIN)) {
BLI_ghash_insert(srna->cont.prophash, (void *)prop->identifier, prop);
+ }
+ }
}
+ BLI_assert(srna->flag & STRUCT_PUBLIC_NAMESPACE);
+ BLI_ghash_insert(BLENDER_RNA.structs_map, (void *)srna->identifier, srna);
+ BLENDER_RNA.structs_len += 1;
}
}
@@ -378,6 +387,7 @@ static bool rna_idproperty_verify_valid(PointerRNA *ptr, PropertyRNA *prop, IDPr
return false;
break;
case IDP_GROUP:
+ case IDP_ID:
if (prop->type != PROP_POINTER)
return false;
break;
@@ -393,7 +403,8 @@ static PropertyRNA *typemap[IDP_NUMTYPES] = {
(PropertyRNA *)&rna_PropertyGroupItem_int,
(PropertyRNA *)&rna_PropertyGroupItem_float,
NULL, NULL, NULL,
- (PropertyRNA *)&rna_PropertyGroupItem_group, NULL,
+ (PropertyRNA *)&rna_PropertyGroupItem_group,
+ (PropertyRNA *)&rna_PropertyGroupItem_id,
(PropertyRNA *)&rna_PropertyGroupItem_double,
(PropertyRNA *)&rna_PropertyGroupItem_idp_array
};
@@ -508,13 +519,7 @@ static const char *rna_ensure_property_name(const PropertyRNA *prop)
StructRNA *RNA_struct_find(const char *identifier)
{
- StructRNA *type;
- if (identifier) {
- for (type = BLENDER_RNA.structs.first; type; type = type->cont.next)
- if (STREQ(type->identifier, identifier))
- return type;
- }
- return NULL;
+ return BLI_ghash_lookup(BLENDER_RNA.structs_map, identifier);
}
const char *RNA_struct_identifier(const StructRNA *type)
@@ -585,6 +590,21 @@ bool RNA_struct_idprops_register_check(const StructRNA *type)
return (type->flag & STRUCT_NO_IDPROPERTIES) == 0;
}
+bool RNA_struct_idprops_datablock_allowed(const StructRNA *type)
+{
+ return (type->flag & (STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_NO_IDPROPERTIES)) == 0;
+}
+
+/**
+ * Whether given type implies datablock usage by IDProperties.
+ * This is used to prevent classes allowed to have IDProperties, but not datablock ones, to indirectly use some
+ * (e.g. by assigning an IDP_GROUP containing some IDP_ID pointers...).
+ */
+bool RNA_struct_idprops_contains_datablock(const StructRNA *type)
+{
+ return (type->flag & (STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES | STRUCT_ID)) != 0;
+}
+
/* remove an id-property */
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier)
{
@@ -626,8 +646,11 @@ PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
/* id prop lookup, not so common */
PropertyRNA *r_prop = NULL;
PointerRNA r_ptr; /* only support single level props */
- if (RNA_path_resolve(ptr, identifier, &r_ptr, &r_prop) && (r_ptr.type == ptr->type) && (r_ptr.data == ptr->data))
+ if (RNA_path_resolve_property(ptr, identifier, &r_ptr, &r_prop) &&
+ (r_ptr.type == ptr->type) && (r_ptr.data == ptr->data))
+ {
return r_prop;
+ }
}
else {
/* most common case */
@@ -792,6 +815,89 @@ char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, i
return NULL;
}
+/**
+ * Use when registering structs with the #STRUCT_PUBLIC_NAMESPACE flag.
+ */
+bool RNA_struct_available_or_report(ReportList *reports, const char *identifier)
+{
+ const StructRNA *srna_exists = RNA_struct_find(identifier);
+ if (UNLIKELY(srna_exists != NULL)) {
+ /* Use comprehensive string construction since this is such a rare occurrence
+ * and information here may cut down time troubleshooting. */
+ DynStr *dynstr = BLI_dynstr_new();
+ BLI_dynstr_appendf(dynstr, "Type identifier '%s' is already in use: '", identifier);
+ BLI_dynstr_append(dynstr, srna_exists->identifier);
+ int i = 0;
+ if (srna_exists->base) {
+ for (const StructRNA *base = srna_exists->base; base; base = base->base) {
+ BLI_dynstr_append(dynstr, "(");
+ BLI_dynstr_append(dynstr, base->identifier);
+ i += 1;
+ }
+ while (i--) {
+ BLI_dynstr_append(dynstr, ")");
+ }
+ }
+ BLI_dynstr_append(dynstr, "'.");
+ char *result = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+ BKE_report(reports, RPT_ERROR, result);
+ MEM_freeN(result);
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+bool RNA_struct_bl_idname_ok_or_report(ReportList *reports, const char *identifier, const char *sep)
+{
+ const int len_sep = strlen(sep);
+ const int len_id = strlen(identifier);
+ const char *p = strstr(identifier, sep);
+ /* TODO: make error, for now warning until add-ons update. */
+#if 1
+ const int report_level = RPT_WARNING;
+ const bool failure = true;
+#else
+ const int report_level = RPT_ERROR;
+ const bool failure = false;
+#endif
+ if (p == NULL || p == identifier || p + len_sep >= identifier + len_id) {
+ BKE_reportf(reports, report_level, "'%s' doesn't contain '%s' with prefix & suffix", identifier, sep);
+ return failure;
+ }
+
+ const char *c, *start, *end, *last;
+ start = identifier;
+ end = p;
+ last = end - 1;
+ for (c = start; c != end; c++) {
+ if (((*c >= 'A' && *c <= 'Z') ||
+ ((c != start) && (*c >= '0' && *c <= '9')) ||
+ ((c != start) && (c != last) && (*c == '_'))) == 0)
+ {
+ BKE_reportf(reports, report_level, "'%s' doesn't have upper case alpha-numeric prefix", identifier);
+ return failure;
+ }
+ }
+
+ start = p + len_sep;
+ end = identifier + len_id;
+ last = end - 1;
+ for (c = start; c != end; c++) {
+ if (((*c >= 'A' && *c <= 'Z') ||
+ (*c >= 'a' && *c <= 'z') ||
+ (*c >= '0' && *c <= '9') ||
+ ((c != start) && (c != last) && (*c == '_'))) == 0)
+ {
+ BKE_reportf(reports, report_level, "'%s' doesn't have an alpha-numeric suffix", identifier);
+ return failure;
+ }
+ }
+ return true;
+}
+
/* Property Information */
const char *RNA_property_identifier(PropertyRNA *prop)
@@ -824,6 +930,11 @@ int RNA_property_flag(PropertyRNA *prop)
return rna_ensure_property(prop)->flag;
}
+bool RNA_property_builtin(PropertyRNA *prop)
+{
+ return (rna_ensure_property(prop)->flag_internal & PROP_INTERN_BUILTIN) != 0;
+}
+
void *RNA_property_py_data_get(PropertyRNA *prop)
{
return prop->py_data;
@@ -1194,13 +1305,20 @@ int RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *va
if (prop->type == PROP_POINTER) {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
- if (pprop->poll)
- return pprop->poll(ptr, *value);
+
+ if (pprop->poll) {
+ if (rna_idproperty_check(&prop, ptr)) {
+ return ((PropPointerPollFuncPy) pprop->poll)(ptr, *value, prop);
+ }
+ else {
+ return pprop->poll(ptr, *value);
+ }
+ }
return 1;
}
- printf("%s %s: is not a pointer property.\n", __func__, prop->identifier);
+ printf("%s: %s is not a pointer property.\n", __func__, prop->identifier);
return 0;
}
@@ -2960,6 +3078,10 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
if ((idprop = rna_idproperty_check(&prop, ptr))) {
pprop = (PointerPropertyRNA *)prop;
+ if (RNA_struct_is_ID(pprop->type)) {
+ return rna_pointer_inherit_refine(ptr, pprop->type, IDP_Id(idprop));
+ }
+
/* for groups, data is idprop itself */
if (pprop->typef)
return rna_pointer_inherit_refine(ptr, pprop->typef(ptr), idprop);
@@ -2982,22 +3104,32 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value)
{
- /*IDProperty *idprop;*/
-
+ PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
BLI_assert(RNA_property_type(prop) == PROP_POINTER);
- if ((/*idprop = */ rna_idproperty_check(&prop, ptr))) {
- /* not supported */
- /* rna_idproperty_touch(idprop); */
+ /* Check types */
+ if (ptr_value.type != NULL && !RNA_struct_is_a(ptr_value.type, pprop->type)) {
+ printf("%s: expected %s type, not %s.\n", __func__, pprop->type->identifier, ptr_value.type->identifier);
+ return;
}
- else {
- PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
- if (pprop->set &&
- !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) &&
- !((prop->flag & PROP_ID_SELF_CHECK) && ptr->id.data == ptr_value.id.data))
- {
- pprop->set(ptr, ptr_value);
+ /* RNA */
+ if (pprop->set &&
+ !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) &&
+ !((prop->flag & PROP_ID_SELF_CHECK) && ptr->id.data == ptr_value.id.data))
+ {
+ pprop->set(ptr, ptr_value);
+ }
+ /* IDProperty */
+ else if (prop->flag & PROP_EDITABLE) {
+ IDPropertyTemplate val = {0};
+ IDProperty *group;
+
+ val.id = ptr_value.data;
+
+ group = RNA_struct_idprops(ptr, true);
+ if (group) {
+ IDP_ReplaceInGroup(group, IDP_New(IDP_ID, &val, prop->identifier));
}
}
}
@@ -3107,7 +3239,7 @@ void RNA_property_collection_skip(CollectionPropertyIterator *iter, int num)
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(iter->prop);
int i;
- if (num > 1 && (iter->idprop || (cprop->property.flag & PROP_RAW_ARRAY))) {
+ if (num > 1 && (iter->idprop || (cprop->property.flag_internal & PROP_INTERN_RAW_ARRAY))) {
/* fast skip for array */
ArrayIterator *internal = &iter->internal.array;
@@ -3449,7 +3581,7 @@ int RNA_property_collection_raw_array(PointerRNA *ptr, PropertyRNA *prop, Proper
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
- if (!(prop->flag & PROP_RAW_ARRAY) || !(itemprop->flag & PROP_RAW_ACCESS))
+ if (!(prop->flag_internal & PROP_INTERN_RAW_ARRAY) || !(itemprop->flag_internal & PROP_INTERN_RAW_ACCESS))
return 0;
RNA_property_collection_begin(ptr, prop, &iter);
@@ -5540,6 +5672,9 @@ static char *rna_pointer_as_string__bldata(PointerRNA *ptr)
return BLI_strdup("None");
}
else if (RNA_struct_is_ID(ptr->type)) {
+ if (ptr->id.data == NULL) {
+ return BLI_strdup("None");
+ }
return RNA_path_full_ID_py(ptr->id.data);
}
else {
@@ -5547,9 +5682,13 @@ static char *rna_pointer_as_string__bldata(PointerRNA *ptr)
}
}
-char *RNA_pointer_as_string(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *prop_ptr, PointerRNA *ptr_prop)
+char *RNA_pointer_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop_ptr, PointerRNA *ptr_prop)
{
- if (RNA_property_flag(prop_ptr) & PROP_IDPROPERTY) {
+ IDProperty *prop;
+ if (ptr_prop->data == NULL) {
+ return BLI_strdup("None");
+ }
+ else if ((prop = rna_idproperty_check(&prop_ptr, ptr)) && prop->type != IDP_ID) {
return RNA_pointer_as_string_id(C, ptr_prop);
}
else {
@@ -5570,15 +5709,16 @@ char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr,
DynStr *dynstr = BLI_dynstr_new();
char *cstring, *buf;
bool first_iter = true;
- int flag;
+ int flag, flag_parameter;
RNA_PROP_BEGIN (ptr, propptr, iterprop)
{
prop = propptr.data;
flag = RNA_property_flag(prop);
+ flag_parameter = RNA_parameter_flag(prop);
- if (as_function && (flag & PROP_OUTPUT)) {
+ if (as_function && (flag_parameter & PARM_OUTPUT)) {
continue;
}
@@ -5592,7 +5732,7 @@ char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr,
continue;
}
- if (as_function && (flag & PROP_REQUIRED)) {
+ if (as_function && (prop->flag_parameter & PARM_REQUIRED)) {
/* required args don't have useful defaults */
BLI_dynstr_appendf(dynstr, first_iter ? "%s" : ", %s", arg_name);
first_iter = false;
@@ -5913,6 +6053,11 @@ const ListBase *RNA_function_defined_parameters(FunctionRNA *func)
/* Utility */
+int RNA_parameter_flag(PropertyRNA *prop)
+{
+ return (int)rna_ensure_property(prop)->flag_parameter;
+}
+
ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *UNUSED(ptr), FunctionRNA *func)
{
PropertyRNA *parm;
@@ -5926,7 +6071,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *UNUSE
for (parm = func->cont.properties.first; parm; parm = parm->next) {
alloc_size += rna_parameter_size(parm);
- if (parm->flag & PROP_OUTPUT)
+ if (parm->flag_parameter & PARM_OUTPUT)
parms->ret_count++;
else
parms->arg_count++;
@@ -5949,7 +6094,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *UNUSE
data_alloc->array = NULL;
}
- if (!(parm->flag & PROP_REQUIRED) && !(parm->flag & PROP_DYNAMIC)) {
+ if (!(parm->flag_parameter & PARM_REQUIRED) && !(parm->flag & PROP_DYNAMIC)) {
switch (parm->type) {
case PROP_BOOLEAN:
if (parm->arraydimension) memcpy(data, ((BoolPropertyRNA *)parm)->defaultarray, size);
@@ -6373,7 +6518,7 @@ static int rna_function_parameter_parse(PointerRNA *ptr, PropertyRNA *prop, Prop
ptype = RNA_property_pointer_type(ptr, prop);
- if (prop->flag & PROP_RNAPTR) {
+ if (prop->flag_parameter & PARM_RNAPTR) {
*((PointerRNA *)dest) = *((PointerRNA *)src);
break;
}
@@ -6384,7 +6529,7 @@ static int rna_function_parameter_parse(PointerRNA *ptr, PropertyRNA *prop, Prop
tid, fid, pid, RNA_struct_identifier(ptype), RNA_struct_identifier(srna));
return -1;
}
-
+
*((void **)dest) = *((void **)src);
break;
@@ -6443,7 +6588,7 @@ int RNA_function_call_direct_va(bContext *C, ReportList *reports, PointerRNA *pt
ParameterIterator iter;
PropertyRNA *pret, *parm;
PropertyType type;
- int i, ofs, flen, flag, len, alen, err = 0;
+ int i, ofs, flen, flag_parameter, len, alen, err = 0;
const char *tid, *fid, *pid = NULL;
char ftype;
void **retdata = NULL;
@@ -6460,20 +6605,20 @@ int RNA_function_call_direct_va(bContext *C, ReportList *reports, PointerRNA *pt
for (i = 0, ofs = 0; iter.valid; RNA_parameter_list_next(&iter), i++) {
parm = iter.parm;
- flag = RNA_property_flag(parm);
+ flag_parameter = RNA_parameter_flag(parm);
if (parm == pret) {
retdata = iter.data;
continue;
}
- else if (flag & PROP_OUTPUT) {
+ else if (flag_parameter & PARM_OUTPUT) {
continue;
}
pid = RNA_property_identifier(parm);
if (ofs >= flen || format[ofs] == 'N') {
- if (flag & PROP_REQUIRED) {
+ if (parm->flag_parameter & PARM_REQUIRED) {
err = -1;
fprintf(stderr, "%s.%s: missing required parameter %s\n", tid, fid, pid);
break;
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 3f2c0f3d434..d398ce95a52 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -34,6 +34,8 @@
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_action.h"
#include "RNA_access.h"
@@ -586,7 +588,7 @@ static void rna_def_action_groups(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Action_groups_new");
RNA_def_function_ui_description(func, "Create a new action group and add it to the action");
parm = RNA_def_string(func, "name", "Group", 0, "", "New name for the action group");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "action_group", "ActionGroup", "", "Newly created action group");
RNA_def_function_return(func, parm);
@@ -596,8 +598,8 @@ static void rna_def_action_groups(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove action group");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "action_group", "ActionGroup", "", "Action 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
@@ -617,7 +619,7 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add an F-Curve to the action");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path to use");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX);
RNA_def_string(func, "action_group", NULL, 0, "Action Group", "Acton group to add this F-Curve into");
@@ -630,9 +632,8 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
"of all F-Curves in the action.");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX);
-
parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "The found F-Curve, or None if it doesn't exist");
RNA_def_function_return(func, parm);
@@ -641,8 +642,8 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove action group");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "F-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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_action_pose_markers(BlenderRNA *brna, PropertyRNA *cprop)
@@ -661,8 +662,7 @@ static void rna_def_action_pose_markers(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Action_pose_markers_new");
RNA_def_function_ui_description(func, "Add a pose marker to the action");
parm = RNA_def_string(func, "name", "Marker", 0, NULL, "New name for the marker (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Newly created marker");
RNA_def_function_return(func, parm);
@@ -670,8 +670,8 @@ static void rna_def_action_pose_markers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a timeline marker");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Timeline marker 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "TimelineMarker");
@@ -733,6 +733,7 @@ static void rna_def_action(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "ID Root Type",
"Type of ID block that action can be used on - "
"DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
/* API calls */
RNA_api_action(srna);
diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c
index a09853eaddc..004acbe4dbd 100644
--- a/source/blender/makesrna/intern/rna_actuator.c
+++ b/source/blender/makesrna/intern/rna_actuator.c
@@ -32,8 +32,9 @@
#include "DNA_actuator_types.h"
#include "DNA_scene_types.h" /* for MAXFRAME */
-#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_actuator_api.c b/source/blender/makesrna/intern/rna_actuator_api.c
index 4a34961964d..23fdd8a1d5b 100644
--- a/source/blender/makesrna/intern/rna_actuator_api.c
+++ b/source/blender/makesrna/intern/rna_actuator_api.c
@@ -63,13 +63,13 @@ void RNA_api_actuator(StructRNA *srna)
func = RNA_def_function(srna, "link", "rna_Actuator_link");
RNA_def_function_ui_description(func, "Link the actuator to a controller");
parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to link to");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_update(parm, NC_LOGIC, NULL);
func = RNA_def_function(srna, "unlink", "rna_Actuator_unlink");
RNA_def_function_ui_description(func, "Unlink the actuator from a controller");
parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to unlink from");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_update(parm, NC_LOGIC, NULL);
}
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index cdbf7582fa7..47b2c84a67f 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -32,6 +32,8 @@
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
@@ -244,8 +246,9 @@ static void rna_KeyingSetInfo_unregister(Main *bmain, StructRNA *type)
ANIM_keyingset_info_unregister(bmain, ksi);
}
-static StructRNA *rna_KeyingSetInfo_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_KeyingSetInfo_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
KeyingSetInfo dummyksi = {NULL};
KeyingSetInfo *ksi;
@@ -268,9 +271,10 @@ static StructRNA *rna_KeyingSetInfo_register(Main *bmain, ReportList *reports, v
/* check if we have registered this info before, and remove it */
ksi = ANIM_keyingset_info_find_name(dummyksi.idname);
- if (ksi && ksi->ext.srna)
+ if (ksi && ksi->ext.srna) {
rna_KeyingSetInfo_unregister(bmain, ksi->ext.srna);
-
+ }
+
/* create a new KeyingSetInfo type */
ksi = MEM_callocN(sizeof(KeyingSetInfo), "python keying set info");
memcpy(ksi, &dummyksi, sizeof(KeyingSetInfo));
@@ -693,27 +697,27 @@ static void rna_def_keyingset_info(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_REGISTER);
RNA_def_function_return(func, RNA_def_boolean(func, "ok", 1, "", ""));
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* iterator */
func = RNA_def_function(srna, "iterator", NULL);
RNA_def_function_ui_description(func, "Call generate() on the structs which have properties to be keyframed");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "ks", "KeyingSet", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* generate */
func = RNA_def_function(srna, "generate", NULL);
RNA_def_function_ui_description(func, "Add Paths to the Keying Set to keyframe the properties of the given data");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "ks", "KeyingSet", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "data", "AnyType", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
}
static void rna_def_keyingset_path(BlenderRNA *brna)
@@ -742,6 +746,7 @@ static void rna_def_keyingset_path(BlenderRNA *brna)
RNA_def_property_enum_default(prop, ID_OB);
RNA_def_property_enum_funcs(prop, NULL, "rna_ksPath_id_type_set", NULL);
RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
RNA_def_property_update(prop, NC_SCENE | ND_KEYINGSET | NA_EDITED, NULL); /* XXX: maybe a bit too noisy */
/* Group */
@@ -807,11 +812,11 @@ static void rna_def_keyingset_paths(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
/* ID-block for target */
parm = RNA_def_pointer(func, "target_id", "ID", "Target ID", "ID data-block for the destination");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* rna-path */
/* XXX hopefully this is long enough */
parm = RNA_def_string(func, "data_path", NULL, 256, "Data-Path", "RNA-Path to destination property");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* index (defaults to -1 for entire array) */
RNA_def_int(func, "index", -1, -1, INT_MAX, "Index",
"The index of the destination property (i.e. axis of Location/Rotation/etc.), "
@@ -829,8 +834,8 @@ static void rna_def_keyingset_paths(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
/* path to remove */
parm = RNA_def_pointer(func, "path", "KeyingSetPath", "Path", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* Remove All Paths */
@@ -939,8 +944,8 @@ static void rna_api_animdata_nla_tracks(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Remove a NLA Track");
parm = RNA_def_pointer(func, "track", "NlaTrack", "", "NLA Track 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "NlaTrack");
@@ -979,7 +984,7 @@ static void rna_api_animdata_drivers(BlenderRNA *brna, PropertyRNA *cprop)
"of all driver F-Curves.");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX);
/* return type */
parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "The found F-Curve, or None if it doesn't exist");
diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c
index 8e42e68ed1e..eea24bfb1e0 100644
--- a/source/blender/makesrna/intern/rna_animviz.c
+++ b/source/blender/makesrna/intern/rna_animviz.c
@@ -153,7 +153,20 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
prop = RNA_def_property(srna, "length", PROP_INT, PROP_TIME);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Length", "Number of frames cached");
-
+
+ /* Custom Color */
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Color", "Custom color for motion path");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* Line width */
+ prop = RNA_def_property(srna, "line_thickness", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "line_thickness");
+ RNA_def_property_range(prop, 1, 6);
+ RNA_def_property_ui_text(prop, "Line thickness", "Line thickness for drawing path");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
/* Settings */
prop = RNA_def_property(srna, "use_bone_head", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_BHEAD);
@@ -164,6 +177,19 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
prop = RNA_def_property(srna, "is_modified", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_EDIT);
RNA_def_property_ui_text(prop, "Edit Path", "Path is being edited");
+
+ /* Use custom color */
+ prop = RNA_def_property(srna, "use_custom_color", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_CUSTOM);
+ RNA_def_property_ui_text(prop, "Custom colors", "Use custom color for this motion path");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* Draw lines between keyframes */
+ prop = RNA_def_property(srna, "lines", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_LINES);
+ RNA_def_property_ui_text(prop, "Lines", "Draw straight lines between keyframe points");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
}
/* --- */
@@ -337,6 +363,7 @@ static void rna_def_animviz_paths(BlenderRNA *brna)
"Number of frames to show after the current frame "
"(only for 'Around Current Frame' Onion-skinning method)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); /* XXX since this is only for 3d-view drawing */
+
}
/* --- */
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 5c7f51516cb..ec700eb00de 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -187,6 +187,9 @@ static void rna_Bone_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
}
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ /* spaces that show animation data of the selected bone need updating */
+ WM_main_add_notifier(NC_ANIMATION | ND_ANIMCHAN, id);
}
static char *rna_Bone_path(PointerRNA *ptr)
@@ -477,7 +480,7 @@ static int rna_Armature_is_editmode_get(PointerRNA *ptr)
static void rna_Armature_transform(struct bArmature *arm, float *mat)
{
- ED_armature_transform(arm, (float (*)[4])mat);
+ ED_armature_transform(arm, (float (*)[4])mat, true);
}
#else
@@ -948,8 +951,7 @@ static void rna_def_armature_edit_bones(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new bone");
parm = RNA_def_string(func, "name", "Object", 0, "", "New name for the bone");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "bone", "EditBone", "", "Newly created edit bone");
RNA_def_function_return(func, parm);
@@ -960,16 +962,18 @@ static void rna_def_armature_edit_bones(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove an existing bone from the armature");
/* target to remove*/
parm = RNA_def_pointer(func, "bone", "EditBone", "", "EditBone 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_armature(BlenderRNA *brna)
{
StructRNA *srna;
- FunctionRNA *func;
PropertyRNA *prop;
-
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
static EnumPropertyItem prop_drawtype_items[] = {
{ARM_OCTA, "OCTAHEDRAL", 0, "Octahedral", "Display bones as octahedral shape (default)"},
{ARM_LINE, "STICK", 0, "Stick", "Display bones as simple 2D lines with dots"},
@@ -1005,8 +1009,8 @@ static void rna_def_armature(BlenderRNA *brna)
func = RNA_def_function(srna, "transform", "rna_Armature_transform");
RNA_def_function_ui_description(func, "Transform armature bones by a matrix");
- prop = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* Animation Data */
rna_def_animdata_common(srna);
diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.c
index 1a4a9492543..0616331bc05 100644
--- a/source/blender/makesrna/intern/rna_armature_api.c
+++ b/source/blender/makesrna/intern/rna_armature_api.c
@@ -67,7 +67,7 @@ void RNA_api_armature_edit_bone(StructRNA *srna)
RNA_def_function_ui_description(func, "Align the bone to a localspace roll so the Z axis "
"points in the direction of the vector given");
parm = RNA_def_float_vector(func, "vector", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_api_bone(StructRNA *srna)
@@ -79,7 +79,7 @@ void RNA_api_bone(StructRNA *srna)
RNA_def_function_ui_description(func, "Calculate bone envelope at given point");
parm = RNA_def_float_vector_xyz(func, "point", 3, NULL, -FLT_MAX, FLT_MAX, "Point",
"Position in 3d space to evaluate", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return value */
parm = RNA_def_float(func, "factor", 0, -FLT_MAX, FLT_MAX, "Factor", "Envelope factor", -FLT_MAX, FLT_MAX);
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index ac348c1750c..2b2df861f2d 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -94,6 +94,21 @@ EnumPropertyItem rna_enum_brush_vertex_tool_items[] = {
{PAINT_BLEND_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", "Blur the color with surrounding values"},
{PAINT_BLEND_LIGHTEN, "LIGHTEN", ICON_BRUSH_LIGHTEN, "Lighten", "Use lighten blending mode while painting"},
{PAINT_BLEND_DARKEN, "DARKEN", ICON_BRUSH_DARKEN, "Darken", "Use darken blending mode while painting"},
+ {PAINT_BLEND_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", "Use average blending mode while painting"},
+ {PAINT_BLEND_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", "Use smear blending mode while painting"},
+ {PAINT_BLEND_COLORDODGE, "COLORDODGE", ICON_BRUSH_BLUR, "Color Dodge", "Use color dodge blending mode while painting" },
+ {PAINT_BLEND_DIFFERENCE, "DIFFERENCE", ICON_BRUSH_BLUR, "Difference", "Use difference blending mode while painting"},
+ {PAINT_BLEND_SCREEN, "SCREEN", ICON_BRUSH_BLUR, "Screen", "Use screen blending mode while painting"},
+ {PAINT_BLEND_HARDLIGHT, "HARDLIGHT", ICON_BRUSH_BLUR, "Hardlight", "Use hardlight blending mode while painting"},
+ {PAINT_BLEND_OVERLAY, "OVERLAY", ICON_BRUSH_BLUR, "Overlay", "Use overlay blending mode while painting"},
+ {PAINT_BLEND_SOFTLIGHT, "SOFTLIGHT", ICON_BRUSH_BLUR, "Softlight", "Use softlight blending mode while painting"},
+ {PAINT_BLEND_EXCLUSION, "EXCLUSION", ICON_BRUSH_BLUR, "Exclusion", "Use exclusion blending mode while painting"},
+ {PAINT_BLEND_LUMINOCITY, "LUMINOCITY", ICON_BRUSH_BLUR, "Luminocity", "Use luminocity blending mode while painting"},
+ {PAINT_BLEND_SATURATION, "SATURATION", ICON_BRUSH_BLUR, "Saturation", "Use saturation blending mode while painting"},
+ {PAINT_BLEND_HUE, "HUE", ICON_BRUSH_BLUR, "Hue", "Use hue blending mode while painting"},
+ {PAINT_BLEND_ALPHA_SUB, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"},
+ {PAINT_BLEND_ALPHA_ADD, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"},
+
{0, NULL, 0, NULL, NULL}
};
@@ -223,11 +238,7 @@ static int rna_SculptToolCapabilities_has_sculpt_plane_get(PointerRNA *ptr)
static int rna_SculptToolCapabilities_has_secondary_color_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM(br->sculpt_tool,
- SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS,
- SCULPT_TOOL_CREASE, SCULPT_TOOL_DRAW, SCULPT_TOOL_FILL,
- SCULPT_TOOL_FLATTEN, SCULPT_TOOL_INFLATE, SCULPT_TOOL_PINCH,
- SCULPT_TOOL_SCRAPE);
+ return BKE_brush_sculpt_has_secondary_color(br);
}
static int rna_SculptToolCapabilities_has_smooth_stroke_get(PointerRNA *ptr)
@@ -1105,7 +1116,20 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Blur Mode", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "falloff_angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "falloff_angle");
+ RNA_def_property_range(prop, 0, M_PI / 2);
+ RNA_def_property_ui_text(prop, "Falloff Angle",
+ "Paint most on faces pointing towards the view according to this angle");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
/* flag */
+ /* This is an enum but its unlikely we add other shapes, so expose as a boolean. */
+ prop = RNA_def_property(srna, "use_projected", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "falloff_shape", BRUSH_AIRBRUSH);
+ RNA_def_property_ui_text(prop, "2D Falloff", "Apply brush influence in 2D circle instead of a sphere");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_airbrush", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_AIRBRUSH);
RNA_def_property_ui_text(prop, "Airbrush", "Keep applying paint effect while holding mouse (spray)");
@@ -1182,6 +1206,11 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Front-Face", "Brush only affects vertexes that face the viewer");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "use_frontface_falloff", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_FRONTFACE_FALLOFF);
+ RNA_def_property_ui_text(prop, "Use Front-Face Falloff", "Blend brush influence by how much they face the front");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_anchor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ANCHORED);
RNA_def_property_ui_text(prop, "Anchored", "Keep the brush anchored to the initial location");
@@ -1248,7 +1277,7 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Restore Mesh", "Allow a single dot to be carefully positioned");
RNA_def_property_update(prop, 0, "rna_Brush_update");
- /* only for projection paint, TODO, other paint modes */
+ /* only for projection paint & vertex paint, TODO, other paint modes */
prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BRUSH_LOCK_ALPHA);
RNA_def_property_ui_text(prop, "Alpha", "When this is disabled, lock alpha while painting");
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 24f2d8174af..5339df34a38 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -508,12 +508,13 @@ static void rna_ColorManagedViewSettings_look_set(PointerRNA *ptr, int value)
}
static EnumPropertyItem *rna_ColorManagedViewSettings_look_itemf(
- bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
+ ColorManagedViewSettings *view = (ColorManagedViewSettings *) ptr->data;
EnumPropertyItem *items = NULL;
int totitem = 0;
- IMB_colormanagement_look_items_add(&items, &totitem);
+ IMB_colormanagement_look_items_add(&items, &totitem, view->view_transform);
RNA_enum_item_end(&items, &totitem);
*r_free = true;
@@ -727,9 +728,9 @@ static void rna_def_curvemap_points_api(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "curvemap_insert");
RNA_def_function_ui_description(func, "Add point to CurveMap");
parm = RNA_def_float(func, "position", 0.0f, -FLT_MAX, FLT_MAX, "Position", "Position to add point", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func, "value", 0.0f, -FLT_MAX, FLT_MAX, "Value", "Value of point", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "point", "CurveMapPoint", "", "New point");
RNA_def_function_return(func, parm);
@@ -737,8 +738,8 @@ static void rna_def_curvemap_points_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Delete point from CurveMap");
parm = RNA_def_pointer(func, "point", "CurveMapPoint", "", "PointElement 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_curvemap(BlenderRNA *brna)
@@ -771,7 +772,7 @@ static void rna_def_curvemap(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Evaluate curve at given location");
parm = RNA_def_float(func, "position", 0.0f, -FLT_MAX, FLT_MAX, "Position", "Position to evaluate curve at", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func, "value", 0.0f, -FLT_MAX, FLT_MAX, "Value", "Value of curve at given location", -FLT_MAX, FLT_MAX);
RNA_def_function_return(func, parm);
}
@@ -889,7 +890,7 @@ static void rna_def_color_ramp_element_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add element to ColorRamp");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_float(func, "position", 0.0f, 0.0f, 1.0f, "Position", "Position to add element", 0.0f, 1.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "element", "ColorRampElement", "", "New element");
RNA_def_function_return(func, parm);
@@ -898,15 +899,17 @@ static void rna_def_color_ramp_element_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Delete element from ColorRamp");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "element", "ColorRampElement", "", "Element 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_color_ramp(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
static EnumPropertyItem prop_interpolation_items[] = {
{COLBAND_INTERP_EASE, "EASE", 0, "Ease", ""},
@@ -974,13 +977,13 @@ static void rna_def_color_ramp(BlenderRNA *brna)
func = RNA_def_function(srna, "evaluate", "rna_ColorRamp_eval");
RNA_def_function_ui_description(func, "Evaluate ColorRamp");
- prop = RNA_def_float(func, "position", 1.0f, 0.0f, 1.0f, "Position", "Evaluate ColorRamp at position", 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_float(func, "position", 1.0f, 0.0f, 1.0f, "Position", "Evaluate ColorRamp at position", 0.0f, 1.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return */
- prop = RNA_def_float_color(func, "color", 4, NULL, -FLT_MAX, FLT_MAX, "Color", "Color at given position",
+ parm = RNA_def_float_color(func, "color", 4, NULL, -FLT_MAX, FLT_MAX, "Color", "Color at given position",
-FLT_MAX, FLT_MAX);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
}
static void rna_def_histogram(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_controller.c b/source/blender/makesrna/intern/rna_controller.c
index ed700916584..3fa9d7ef270 100644
--- a/source/blender/makesrna/intern/rna_controller.c
+++ b/source/blender/makesrna/intern/rna_controller.c
@@ -29,6 +29,7 @@
#include "DNA_object_types.h"
#include "DNA_controller_types.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 22e45964742..7787533d311 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -1257,8 +1257,8 @@ static void rna_def_curve_spline_points(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a spline from a curve");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "spline", "Spline", "", "The spline 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
#endif
}
@@ -1285,8 +1285,8 @@ static void rna_def_curve_spline_bezpoints(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a spline from a curve");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "spline", "Spline", "", "The spline 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
#endif
}
@@ -1307,7 +1307,7 @@ static void rna_def_curve_splines(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Curve_spline_new");
RNA_def_function_ui_description(func, "Add a new spline to the curve");
parm = RNA_def_enum(func, "type", curve_type_items, CU_POLY, "", "type for the new spline");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "spline", "Spline", "", "The newly created spline");
RNA_def_function_return(func, parm);
@@ -1315,8 +1315,8 @@ static void rna_def_curve_splines(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a spline from a curve");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "spline", "Spline", "", "The spline 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "clear", "rna_Curve_spline_clear");
RNA_def_function_ui_description(func, "Remove all splines from a curve");
diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c
index e85511f08e9..be6808567bb 100644
--- a/source/blender/makesrna/intern/rna_curve_api.c
+++ b/source/blender/makesrna/intern/rna_curve_api.c
@@ -45,7 +45,7 @@
#ifdef RNA_RUNTIME
static void rna_Curve_transform(Curve *cu, float *mat, int shape_keys)
{
- BKE_curve_transform(cu, (float (*)[4])mat, shape_keys);
+ BKE_curve_transform(cu, (float (*)[4])mat, shape_keys, true);
DAG_id_tag_update(&cu->id, 0);
}
@@ -59,7 +59,7 @@ void RNA_api_curve(StructRNA *srna)
func = RNA_def_function(srna, "transform", "rna_Curve_transform");
RNA_def_function_ui_description(func, "Transform curve by a matrix");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
func = RNA_def_function(srna, "validate_material_indices", "BKE_curve_material_index_validate");
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 7ff4eaea169..118dd0b15de 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -44,6 +44,8 @@
#include "BLT_translation.h"
+#include "UI_interface.h" /* For things like UI_PRECISION_FLOAT_MAX... */
+
#include "RNA_define.h"
#include "rna_internal.h"
@@ -71,8 +73,8 @@ BlenderDefRNA DefRNA = {NULL, {NULL, NULL}, {NULL, NULL}, NULL, 0, 0, 0, 1, 1};
if (description && (description)[0]) { \
int i = strlen(description); \
if (i > 3 && (description)[i - 1] == '.' && (description)[i - 3] != '.') { \
- fprintf(stderr, "%s: '%s' '%s' description ends with a '.' !\n", \
- __func__, id1 ? id1 : "", id2 ? id2 : ""); \
+ fprintf(stderr, "%s: '%s' description from '%s' '%s' ends with a '.' !\n", \
+ __func__, description, id1 ? id1 : "", id2 ? id2 : ""); \
} \
} (void)0
@@ -135,6 +137,38 @@ void rna_freelistN(ListBase *listbase)
listbase->first = listbase->last = NULL;
}
+static void rna_brna_structs_add(BlenderRNA *brna, StructRNA *srna)
+{
+ rna_addtail(&brna->structs, srna);
+ brna->structs_len += 1;
+
+ /* This exception is only needed for pre-processing.
+ * otherwise we don't allow empty names. */
+ if ((srna->flag & STRUCT_PUBLIC_NAMESPACE) &&
+ (srna->identifier[0] != '\0'))
+ {
+ BLI_ghash_insert(brna->structs_map, (void *)srna->identifier, srna);
+ }
+}
+
+#ifdef RNA_RUNTIME
+static void rna_brna_structs_remove_and_free(BlenderRNA *brna, StructRNA *srna)
+{
+ if ((srna->flag & STRUCT_PUBLIC_NAMESPACE) && brna->structs_map) {
+ if (srna->identifier[0] != '\0') {
+ BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL);
+ }
+ }
+
+ RNA_def_struct_free_pointers(NULL, srna);
+
+ if (srna->flag & STRUCT_RUNTIME) {
+ rna_freelinkN(&brna->structs, srna);
+ }
+ brna->structs_len -= 1;
+}
+#endif
+
StructDefRNA *rna_find_struct_def(StructRNA *srna)
{
StructDefRNA *dsrna;
@@ -534,6 +568,8 @@ BlenderRNA *RNA_create(void)
const char *error_message = NULL;
BLI_listbase_clear(&DefRNA.structs);
+ brna->structs_map = BLI_ghash_str_new_ex(__func__, 2048);
+
DefRNA.error = 0;
DefRNA.preprocess = 1;
@@ -618,7 +654,7 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)
RNA_def_property_free_pointers(prop);
- if (prop->flag & PROP_RUNTIME)
+ if (prop->flag_internal & PROP_INTERN_RUNTIME)
rna_freelinkN(&srna->cont.properties, prop);
}
@@ -630,7 +666,7 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)
RNA_def_property_free_pointers(parm);
- if (parm->flag & PROP_RUNTIME)
+ if (parm->flag_internal & PROP_INTERN_RUNTIME)
rna_freelinkN(&func->cont.properties, parm);
}
@@ -640,10 +676,8 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)
rna_freelinkN(&srna->functions, func);
}
- RNA_def_struct_free_pointers(srna);
- if (srna->flag & STRUCT_RUNTIME)
- rna_freelinkN(&brna->structs, srna);
+ rna_brna_structs_remove_and_free(brna, srna);
#else
UNUSED_VARS(brna, srna);
#endif
@@ -654,6 +688,9 @@ void RNA_free(BlenderRNA *brna)
StructRNA *srna, *nextsrna;
FunctionRNA *func;
+ BLI_ghash_free(brna->structs_map, NULL, NULL);
+ brna->structs_map = NULL;
+
if (DefRNA.preprocess) {
RNA_define_free(brna);
@@ -730,12 +767,19 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN
BLI_listbase_clear(&srna->functions);
srna->py_type = NULL;
+ srna->base = srnafrom;
+
if (DefRNA.preprocess) {
- srna->base = srnafrom;
dsfrom = rna_find_def_struct(srnafrom);
}
- else
- srna->base = srnafrom;
+ else {
+ if (srnafrom->flag & STRUCT_PUBLIC_NAMESPACE_INHERIT) {
+ srna->flag |= STRUCT_PUBLIC_NAMESPACE | STRUCT_PUBLIC_NAMESPACE_INHERIT;
+ }
+ else {
+ srna->flag &= ~(STRUCT_PUBLIC_NAMESPACE | STRUCT_PUBLIC_NAMESPACE_INHERIT);
+ }
+ }
}
srna->identifier = identifier;
@@ -747,7 +791,11 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN
if (!srnafrom)
srna->icon = ICON_DOT;
- rna_addtail(&brna->structs, srna);
+ if (DefRNA.preprocess) {
+ srna->flag |= STRUCT_PUBLIC_NAMESPACE;
+ }
+
+ rna_brna_structs_add(brna, srna);
if (DefRNA.preprocess) {
ds = MEM_callocN(sizeof(StructDefRNA), "StructDefRNA");
@@ -771,7 +819,7 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN
else {
/* define some builtin properties */
prop = RNA_def_property(&srna->cont, "rna_properties", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_flag(prop, PROP_BUILTIN);
+ prop->flag_internal |= PROP_INTERN_BUILTIN;
RNA_def_property_ui_text(prop, "Properties", "RNA property collection");
if (DefRNA.preprocess) {
@@ -819,10 +867,8 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char *
if (from) {
/* find struct to derive from */
- for (srnafrom = brna->structs.first; srnafrom; srnafrom = srnafrom->cont.next)
- if (STREQ(srnafrom->identifier, from))
- break;
-
+ /* Inline RNA_struct_find(...) because it wont link from here. */
+ srnafrom = BLI_ghash_lookup(brna->structs_map, from);
if (!srnafrom) {
fprintf(stderr, "%s: struct %s not found to define %s.\n", __func__, from, identifier);
DefRNA.error = 1;
@@ -901,10 +947,7 @@ void RNA_def_struct_nested(BlenderRNA *brna, StructRNA *srna, const char *struct
StructRNA *srnafrom;
/* find struct to derive from */
- for (srnafrom = brna->structs.first; srnafrom; srnafrom = srnafrom->cont.next)
- if (STREQ(srnafrom->identifier, structname))
- break;
-
+ srnafrom = BLI_ghash_lookup(brna->structs_map, structname);
if (!srnafrom) {
fprintf(stderr, "%s: struct %s not found for %s.\n", __func__, structname, srna->identifier);
DefRNA.error = 1;
@@ -965,7 +1008,32 @@ void RNA_def_struct_path_func(StructRNA *srna, const char *path)
if (path) srna->path = (StructPathFunc)path;
}
-void RNA_def_struct_identifier(StructRNA *srna, const char *identifier)
+void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier)
+{
+ if (DefRNA.preprocess) {
+ fprintf(stderr, "%s: only at runtime.\n", __func__);
+ return;
+ }
+
+ /* Operator registration may set twice, see: operator_properties_init */
+ if (srna->flag & STRUCT_PUBLIC_NAMESPACE) {
+ if (identifier != srna->identifier) {
+ if (srna->identifier[0] != '\0') {
+ BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL);
+ }
+ if (identifier[0] != '\0') {
+ BLI_ghash_insert(brna->structs_map, (void *)identifier, srna);
+ }
+ }
+ }
+
+ srna->identifier = identifier;
+}
+
+/**
+ * Only used in one case when we name the struct for the purpose of useful error messages.
+ */
+void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier)
{
if (DefRNA.preprocess) {
fprintf(stderr, "%s: only at runtime.\n", __func__);
@@ -1097,7 +1165,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
break;
}
case PROP_POINTER:
- prop->flag |= PROP_THICK_WRAP; /* needed for default behavior when PROP_RNAPTR is set */
+ prop->flag |= PROP_THICK_WRAP; /* needed for default behavior when PARM_RNAPTR is set */
break;
case PROP_ENUM:
case PROP_COLLECTION:
@@ -1189,7 +1257,8 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
}
}
else {
- prop->flag |= PROP_IDPROPERTY | PROP_RUNTIME;
+ prop->flag |= PROP_IDPROPERTY;
+ prop->flag_internal |= PROP_INTERN_RUNTIME;
#ifdef RNA_RUNTIME
if (cont->prophash)
BLI_ghash_insert(cont->prophash, (void *)prop->identifier, prop);
@@ -1201,16 +1270,28 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
return prop;
}
-void RNA_def_property_flag(PropertyRNA *prop, int flag)
+void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
{
prop->flag |= flag;
}
-void RNA_def_property_clear_flag(PropertyRNA *prop, int flag)
+void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag)
{
prop->flag &= ~flag;
}
+void RNA_def_parameter_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter)
+{
+ prop->flag |= flag_property;
+ prop->flag_parameter |= flag_parameter;
+}
+
+void RNA_def_parameter_clear_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter)
+{
+ prop->flag &= ~flag_property;
+ prop->flag_parameter &= ~flag_parameter;
+}
+
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
{
prop->subtype = subtype;
@@ -1326,13 +1407,13 @@ void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, bool consecutive)
* For ints, whole values are used.
*
* \param precision The number of zeros to show
- * (as a whole number - common range is 1 - 6), see PRECISION_FLOAT_MAX
+ * (as a whole number - common range is 1 - 6), see UI_PRECISION_FLOAT_MAX
*/
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
{
StructRNA *srna = DefRNA.laststruct;
-#ifdef DEBUG
+#ifndef NDEBUG
if (min > max) {
fprintf(stderr, "%s: \"%s.%s\", min > max.\n",
__func__, srna->identifier, prop->identifier);
@@ -1345,8 +1426,8 @@ void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double
DefRNA.error = 1;
}
- if (precision < -1 || precision > 10) {
- fprintf(stderr, "%s: \"%s.%s\", step outside range.\n",
+ if (precision < -1 || precision > UI_PRECISION_FLOAT_MAX) {
+ fprintf(stderr, "%s: \"%s.%s\", precision outside range.\n",
__func__, srna->identifier, prop->identifier);
DefRNA.error = 1;
}
@@ -1368,21 +1449,6 @@ void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double
fprop->softmax = (float)max;
fprop->step = (float)step;
fprop->precision = (int)precision;
-#if 0 /* handy but annoying */
- if (DefRNA.preprocess) {
- /* check we're not over PRECISION_FLOAT_MAX */
- if (fprop->precision > 6) {
- fprintf(stderr, "%s: \"%s.%s\", precision value over maximum.\n",
- __func__, srna->identifier, prop->identifier);
- DefRNA.error = 1;
- }
- else if (fprop->precision < 1) {
- fprintf(stderr, "%s: \"%s.%s\", precision value under minimum.\n",
- __func__, srna->identifier, prop->identifier);
- DefRNA.error = 1;
- }
- }
-#endif
break;
}
default:
@@ -2155,6 +2221,16 @@ void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func)
prop->update = (void *)func;
}
+void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func)
+{
+ if (prop->type == PROP_POINTER) {
+ ((PointerPropertyRNA *)prop)->poll = func;
+ }
+ else {
+ fprintf(stderr, "%s: %s is not a Pointer Property.\n", __func__, prop->identifier);
+ }
+}
+
void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength)
{
if (!DefRNA.preprocess) {
@@ -2969,6 +3045,9 @@ PropertyRNA *RNA_def_pointer_runtime(StructOrFunctionRNA *cont_, const char *ide
prop = RNA_def_property(cont, identifier, PROP_POINTER, PROP_NONE);
RNA_def_property_struct_runtime(prop, type);
+ if ((type->flag & STRUCT_ID) != 0) {
+ prop->flag |= PROP_EDITABLE;
+ }
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
@@ -3097,7 +3176,7 @@ void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret)
void RNA_def_function_output(FunctionRNA *UNUSED(func), PropertyRNA *ret)
{
- ret->flag |= PROP_OUTPUT;
+ ret->flag_parameter |= PARM_OUTPUT;
}
void RNA_def_function_flag(FunctionRNA *func, int flag)
@@ -3144,12 +3223,13 @@ int rna_parameter_size(PropertyRNA *parm)
StringPropertyRNA *sparm = (StringPropertyRNA *)parm;
return sizeof(char) * sparm->maxlength;
}
- else
+ else {
return sizeof(char *);
+ }
case PROP_POINTER:
{
#ifdef RNA_RUNTIME
- if (parm->flag & PROP_RNAPTR)
+ if (parm->flag_parameter & PARM_RNAPTR)
if (parm->flag & PROP_THICK_WRAP) {
return sizeof(PointerRNA);
}
@@ -3159,7 +3239,7 @@ int rna_parameter_size(PropertyRNA *parm)
else
return sizeof(void *);
#else
- if (parm->flag & PROP_RNAPTR) {
+ if (parm->flag_parameter & PARM_RNAPTR) {
if (parm->flag & PROP_THICK_WRAP) {
return sizeof(PointerRNA);
}
@@ -3235,21 +3315,41 @@ void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
/* Memory management */
#ifdef RNA_RUNTIME
-void RNA_def_struct_duplicate_pointers(StructRNA *srna)
+void RNA_def_struct_duplicate_pointers(BlenderRNA *brna, StructRNA *srna)
{
- if (srna->identifier) srna->identifier = BLI_strdup(srna->identifier);
- if (srna->name) srna->name = BLI_strdup(srna->name);
- if (srna->description) srna->description = BLI_strdup(srna->description);
+ if (srna->identifier) {
+ srna->identifier = BLI_strdup(srna->identifier);
+ if (srna->flag & STRUCT_PUBLIC_NAMESPACE) {
+ BLI_ghash_replace_key(brna->structs_map, (void *)srna->identifier);
+ }
+ }
+ if (srna->name) {
+ srna->name = BLI_strdup(srna->name);
+ }
+ if (srna->description) {
+ srna->description = BLI_strdup(srna->description);
+ }
srna->flag |= STRUCT_FREE_POINTERS;
}
-void RNA_def_struct_free_pointers(StructRNA *srna)
+void RNA_def_struct_free_pointers(BlenderRNA *brna, StructRNA *srna)
{
if (srna->flag & STRUCT_FREE_POINTERS) {
- if (srna->identifier) MEM_freeN((void *)srna->identifier);
- if (srna->name) MEM_freeN((void *)srna->name);
- if (srna->description) MEM_freeN((void *)srna->description);
+ if (srna->identifier) {
+ if (srna->flag & STRUCT_PUBLIC_NAMESPACE) {
+ if (brna != NULL) {
+ BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL);
+ }
+ }
+ MEM_freeN((void *)srna->identifier);
+ }
+ if (srna->name) {
+ MEM_freeN((void *)srna->name);
+ }
+ if (srna->description) {
+ MEM_freeN((void *)srna->description);
+ }
}
}
@@ -3357,12 +3457,12 @@ void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA
break;
}
- prop->flag |= PROP_FREE_POINTERS;
+ prop->flag_internal |= PROP_INTERN_FREE_POINTERS;
}
void RNA_def_property_free_pointers(PropertyRNA *prop)
{
- if (prop->flag & PROP_FREE_POINTERS) {
+ if (prop->flag_internal & PROP_INTERN_FREE_POINTERS) {
int a;
if (prop->identifier)
@@ -3429,7 +3529,7 @@ static void rna_def_property_free(StructOrFunctionRNA *cont_, PropertyRNA *prop)
{
ContainerRNA *cont = cont_;
- if (prop->flag & PROP_RUNTIME) {
+ if (prop->flag_internal & PROP_INTERN_RUNTIME) {
if (cont->prophash)
BLI_ghash_remove(cont->prophash, prop->identifier, NULL, NULL);
@@ -3449,7 +3549,7 @@ int RNA_def_property_free_identifier(StructOrFunctionRNA *cont_, const char *ide
for (prop = cont->properties.first; prop; prop = prop->next) {
if (STREQ(prop->identifier, identifier)) {
- if (prop->flag & PROP_RUNTIME) {
+ if (prop->flag_internal & PROP_INTERN_RUNTIME) {
rna_def_property_free(cont_, prop);
return 1;
}
@@ -3460,7 +3560,7 @@ int RNA_def_property_free_identifier(StructOrFunctionRNA *cont_, const char *ide
}
return 0;
}
-#endif
+#endif /* RNA_RUNTIME */
const char *RNA_property_typename(PropertyType type)
{
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
index 8ac1e2acc60..2748bd8b877 100644
--- a/source/blender/makesrna/intern/rna_depsgraph.c
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -93,12 +93,11 @@ static void rna_def_depsgraph(BlenderRNA *brna)
func = RNA_def_function(srna, "debug_graphviz", "rna_Depsgraph_debug_graphviz");
parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name",
"File in which to store graphviz debug output");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "debug_rebuild", "rna_Depsgraph_debug_rebuild");
RNA_def_function_flag(func, FUNC_USE_MAIN);
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
+
func = RNA_def_function(srna, "debug_stats", "rna_Depsgraph_debug_stats");
RNA_def_function_ui_description(func, "Report the number of elements in the Dependency Graph");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index fc2b028e829..4bb7f3a9ffd 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -651,9 +651,9 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
func = RNA_def_function(srna, "output_exists", "rna_DynamicPaint_is_output_exists");
RNA_def_function_ui_description(func, "Checks if surface output layer of given name exists");
parm = RNA_def_pointer(func, "object", "Object", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_int(func, "index", 0, 0, 1, "Index", "", 0, 1);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_boolean(func, "exists", 0, "", "");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 1d3b65bb7ba..ad63a652b12 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -35,6 +35,8 @@
#include "BLI_math.h"
+#include "BLT_translation.h"
+
#include "BKE_action.h"
#include "RNA_access.h"
@@ -763,6 +765,38 @@ static void rna_FModifierStepped_end_frame_range(PointerRNA *ptr, float *min, fl
*max = MAXFRAMEF;
}
+static void rna_FModifierStepped_frame_start_set(PointerRNA *ptr, float value)
+{
+ FModifier *fcm = (FModifier *)ptr->data;
+ FMod_Stepped *data = fcm->data;
+
+ float prop_clamp_min = -FLT_MAX, prop_clamp_max = FLT_MAX, prop_soft_min, prop_soft_max;
+ rna_FModifierStepped_start_frame_range(ptr, &prop_clamp_min, &prop_clamp_max, &prop_soft_min, &prop_soft_max);
+ value = CLAMPIS(value, prop_clamp_min, prop_clamp_max);
+
+ /* Need to set both step-data's start/end and the start/end on the base-data,
+ * or else Restrict-Range doesn't work due to RNA-property shadowing (T52009)
+ */
+ data->start_frame = value;
+ fcm->sfra = value;
+}
+
+static void rna_FModifierStepped_frame_end_set(PointerRNA *ptr, float value)
+{
+ FModifier *fcm = (FModifier *)ptr->data;
+ FMod_Stepped *data = fcm->data;
+
+ float prop_clamp_min = -FLT_MAX, prop_clamp_max = FLT_MAX, prop_soft_min, prop_soft_max;
+ rna_FModifierStepped_end_frame_range(ptr, &prop_clamp_min, &prop_clamp_max, &prop_soft_min, &prop_soft_max);
+ value = CLAMPIS(value, prop_clamp_min, prop_clamp_max);
+
+ /* Need to set both step-data's start/end and the start/end on the base-data,
+ * or else Restrict-Range doesn't work due to RNA-property shadowing (T52009)
+ */
+ data->end_frame = value;
+ fcm->efra = value;
+}
+
static BezTriple *rna_FKeyframe_points_insert(FCurve *fcu, float frame, float value, int keyframe_type, int flag)
{
int index = insert_vert_fcurve(fcu, frame, value, (char)keyframe_type, flag | INSERTKEY_NO_USERPREF);
@@ -1029,7 +1063,7 @@ static void rna_def_fmodifier_envelope_control_points(BlenderRNA *brna, Property
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_float(func, "frame", 0.0f, -FLT_MAX, FLT_MAX, "",
"Frame to add this control-point", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "point", "FModifierEnvelopeControlPoint", "", "Newly created control-point");
RNA_def_function_return(func, parm);
@@ -1037,7 +1071,7 @@ static void rna_def_fmodifier_envelope_control_points(BlenderRNA *brna, Property
RNA_def_function_ui_description(func, "Remove a control-point from an FModifierEnvelope");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "point", "FModifierEnvelopeControlPoint", "", "Control-point to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
}
@@ -1282,13 +1316,13 @@ static void rna_def_fmodifier_stepped(BlenderRNA *brna)
prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "start_frame");
- RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifierStepped_start_frame_range");
+ RNA_def_property_float_funcs(prop, NULL, "rna_FModifierStepped_frame_start_set", "rna_FModifierStepped_start_frame_range");
RNA_def_property_ui_text(prop, "Start Frame", "Frame that modifier's influence starts (if applicable)");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "end_frame");
- RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifierStepped_end_frame_range");
+ RNA_def_property_float_funcs(prop, NULL, "rna_FModifierStepped_frame_end_set", "rna_FModifierStepped_end_frame_range");
RNA_def_property_ui_text(prop, "End Frame", "Frame that modifier's influence ends (if applicable)");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
}
@@ -1448,6 +1482,7 @@ static void rna_def_drivertarget(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, NULL, "rna_DriverTarget_id_type_set", NULL);
RNA_def_property_editable_func(prop, "rna_DriverTarget_id_type_editable");
RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
/* Target Properties - Property to Drive */
@@ -1554,8 +1589,8 @@ static void rna_def_channeldriver_variables(BlenderRNA *brna, PropertyRNA *cprop
RNA_def_function_flag(func, FUNC_USE_REPORTS);
/* target to remove */
parm = RNA_def_pointer(func, "variable", "DriverVariable", "", "Variable to remove from the driver");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_channeldriver(BlenderRNA *brna)
@@ -1774,15 +1809,15 @@ static void rna_def_fcurve_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
/* object to add */
parm = RNA_def_enum(func, "type", rna_enum_fmodifier_type_items, 1, "", "Constraint type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "remove", "rna_FCurve_modifiers_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a modifier from this F-Curve");
/* modifier to remove */
parm = RNA_def_pointer(func, "modifier", "FModifier", "", "Removed modifier");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
/* fcurve.keyframe_points */
@@ -1809,14 +1844,13 @@ static void rna_def_fcurve_keyframe_points(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a keyframe point to a F-Curve");
parm = RNA_def_float(func, "frame", 0.0f, -FLT_MAX, FLT_MAX, "",
"X Value of this keyframe point", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func, "value", 0.0f, -FLT_MAX, FLT_MAX, "",
"Y Value of this keyframe point", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_enum_flag(func, "options", keyframe_flag_items, 0, "", "Keyframe options");
RNA_def_enum(func, "keyframe_type", rna_enum_beztriple_keyframe_type_items, BEZT_KEYTYPE_KEYFRAME, "",
"Type of keyframe to insert");
-
parm = RNA_def_pointer(func, "keyframe", "Keyframe", "", "Newly created keyframe");
RNA_def_function_return(func, parm);
@@ -1828,8 +1862,8 @@ static void rna_def_fcurve_keyframe_points(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove keyframe from an F-Curve");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "keyframe", "Keyframe", "", "Keyframe 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* optional */
RNA_def_boolean(func, "fast", 0, "Fast", "Fast keyframe removal to avoid recalculating the curve each time");
}
@@ -1961,7 +1995,7 @@ static void rna_def_fcurve(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Evaluate F-Curve");
parm = RNA_def_float(func, "frame", 1.0f, -FLT_MAX, FLT_MAX, "Frame",
"Evaluate F-Curve at given frame", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return value */
parm = RNA_def_float(func, "value", 0, -FLT_MAX, FLT_MAX, "Value", "Value of F-Curve specific frame", -FLT_MAX, FLT_MAX);
RNA_def_function_return(func, parm);
@@ -1976,7 +2010,7 @@ static void rna_def_fcurve(BlenderRNA *brna)
/* return value */
parm = RNA_def_float_vector(func, "range", 2, NULL, -FLT_MAX, FLT_MAX, "Range",
"Min/Max values", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
/* -- auto-flag validity (ensures valid handling for data type) -- */
@@ -1986,7 +2020,7 @@ static void rna_def_fcurve(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "data", "AnyType", "Data",
"Data containing the property controlled by given FCurve");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
/* Functions */
diff --git a/source/blender/makesrna/intern/rna_fcurve_api.c b/source/blender/makesrna/intern/rna_fcurve_api.c
index 8551ca609f4..d8ed908f2df 100644
--- a/source/blender/makesrna/intern/rna_fcurve_api.c
+++ b/source/blender/makesrna/intern/rna_fcurve_api.c
@@ -144,9 +144,9 @@ void RNA_api_fcurves(StructRNA *srna)
"Convert current FCurve from keyframes to sample points, if necessary");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_int(func, "start", 0, MINAFRAME, MAXFRAME, "Start Frame", "", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "end", 0, MINAFRAME, MAXFRAME, "End Frame", "", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "convert_to_keyframes", "rna_FCurve_convert_to_keyframes");
RNA_def_function_ui_description(func,
@@ -154,9 +154,9 @@ void RNA_api_fcurves(StructRNA *srna)
"if necessary");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_int(func, "start", 0, MINAFRAME, MAXFRAME, "Start Frame", "", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "end", 0, MINAFRAME, MAXFRAME, "End Frame", "", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_api_drivers(StructRNA *UNUSED(srna))
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
index 091950a8e66..8c3984e4b29 100644
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ b/source/blender/makesrna/intern/rna_fluidsim.c
@@ -185,12 +185,16 @@ static void rna_DomainFluidSettings_memory_estimate_get(PointerRNA *ptr, char *v
#endif
}
-static int rna_DomainFluidSettings_memory_estimate_length(PointerRNA *UNUSED(ptr))
+static int rna_DomainFluidSettings_memory_estimate_length(PointerRNA *ptr)
{
#ifndef WITH_MOD_FLUID
+ UNUSED_VARS(ptr);
return 0;
#else
- return 31;
+ char value[32];
+
+ rna_DomainFluidSettings_memory_estimate_get(ptr, value);
+ return strlen(value);
#endif
}
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 7ba89538b18..79e1e95b27a 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -31,6 +31,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -59,6 +60,7 @@ static EnumPropertyItem parent_type_items[] = {
#include "WM_api.h"
+#include "BKE_animsys.h"
#include "BKE_gpencil.h"
#include "BKE_action.h"
@@ -72,7 +74,7 @@ static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene
{
/* Notify all places where GPencil data lives that the editing state is different */
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
- WM_main_add_notifier(NC_SCENE | ND_MODE, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NC_MOVIECLIP, NULL);
}
static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -352,10 +354,16 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
bGPdata *gpd = ptr->id.data;
bGPDlayer *gpl = ptr->data;
+ char oldname[128] = "";
+ BLI_strncpy(oldname, gpl->info, sizeof(oldname));
+
/* copy the new name into the name slot */
BLI_strncpy_utf8(gpl->info, value, sizeof(gpl->info));
BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
+
+ /* now fix animation paths */
+ BKE_animdata_fix_paths_rename_all(&gpd->id, "layers", oldname, gpl->info);
}
static void rna_GPencil_use_onion_skinning_set(PointerRNA *ptr, const int value)
@@ -585,11 +593,11 @@ static bGPDframe *rna_GPencil_frame_copy(bGPDlayer *layer, bGPDframe *src)
static bGPDlayer *rna_GPencil_layer_new(bGPdata *gpd, const char *name, int setactive)
{
- bGPDlayer *gl = BKE_gpencil_layer_addnew(gpd, name, setactive != 0);
+ bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, name, setactive != 0);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return gl;
+ return gpl;
}
static void rna_GPencil_layer_remove(bGPdata *gpd, ReportList *reports, PointerRNA *layer_ptr)
@@ -776,11 +784,16 @@ static void rna_GPencilPalette_info_set(PointerRNA *ptr, const char *value)
bGPdata *gpd = ptr->id.data;
bGPDpalette *palette = ptr->data;
+ char oldname[64] = "";
+ BLI_strncpy(oldname, palette->info, sizeof(oldname));
+
/* copy the new name into the name slot */
BLI_strncpy_utf8(palette->info, value, sizeof(palette->info));
BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
sizeof(palette->info));
+ /* now fix animation paths */
+ BKE_animdata_fix_paths_rename_all(&gpd->id, "palettes", oldname, palette->info);
}
static char *rna_GPencilPalette_path(PointerRNA *ptr)
@@ -813,14 +826,20 @@ static void rna_GPencilPaletteColor_info_set(PointerRNA *ptr, const char *value)
bGPdata *gpd = ptr->id.data;
bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
bGPDpalettecolor *palcolor = ptr->data;
-
- /* rename all strokes */
- BKE_gpencil_palettecolor_changename(gpd, palcolor->info, value);
+
+ char oldname[64] = "";
+ BLI_strncpy(oldname, palcolor->info, sizeof(oldname));
/* copy the new name into the name slot */
BLI_strncpy_utf8(palcolor->info, value, sizeof(palcolor->info));
BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
sizeof(palcolor->info));
+
+ /* rename all strokes */
+ BKE_gpencil_palettecolor_changename(gpd, oldname, palcolor->info);
+
+ /* now fix animation paths */
+ BKE_animdata_fix_paths_rename_all(&gpd->id, "colors", oldname, palcolor->info);
}
static void rna_GPencilStrokeColor_info_set(PointerRNA *ptr, const char *value)
@@ -1051,8 +1070,8 @@ static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a grease pencil stroke");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "Stroke", "The stroke 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_gpencil_frame(BlenderRNA *brna)
@@ -1112,7 +1131,7 @@ static void rna_def_gpencil_frames_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_int(func, "frame_number", 1, MINAFRAME, MAXFRAME, "Frame Number",
"The frame on which this sketch appears", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "frame", "GPencilFrame", "", "The newly created frame");
RNA_def_function_return(func, parm);
@@ -1120,13 +1139,13 @@ static void rna_def_gpencil_frames_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a grease pencil frame");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "frame", "GPencilFrame", "Frame", "The frame 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "copy", "rna_GPencil_frame_copy");
RNA_def_function_ui_description(func, "Copy a grease pencil frame");
parm = RNA_def_pointer(func, "source", "GPencilFrame", "Source", "The source frame");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "copy", "GPencilFrame", "", "The newly copied frame");
RNA_def_function_return(func, parm);
}
@@ -1242,6 +1261,13 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "use_ghosts_always", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_GHOST_ALWAYS);
+ RNA_def_property_ui_text(prop, "Always Show Ghosts",
+ "Ghosts are shown in renders and animation playback. Useful for special effects (e.g. motion blur)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+
/* Flags */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE);
@@ -1276,13 +1302,13 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ACTIVE);
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencilLayer_active_set");
RNA_def_property_ui_text(prop, "Active", "Set active layer for editing");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
#endif
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_SELECT);
RNA_def_property_ui_text(prop, "Select", "Layer is selected for editing in the Dope Sheet");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, "rna_GPencil_update");
/* XXX keep this option? */
prop = RNA_def_property(srna, "show_points", PROP_BOOLEAN, PROP_NONE);
@@ -1353,8 +1379,8 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_GPencil_layer_new");
RNA_def_function_ui_description(func, "Add a new grease pencil layer");
parm = RNA_def_string(func, "name", "GPencilLayer", MAX_NAME, "Name", "Name of the layer");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_boolean(func, "set_active", 0, "Set Active", "Set the newly created layer to the active layer");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_boolean(func, "set_active", true, "Set Active", "Set the newly created layer to the active layer");
parm = RNA_def_pointer(func, "layer", "GPencilLayer", "", "The newly created layer");
RNA_def_function_return(func, parm);
@@ -1362,22 +1388,23 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a grease pencil layer");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "layer", "GPencilLayer", "", "The layer 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPencilLayer");
RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_layer_get", "rna_GPencil_active_layer_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Layer", "Active grease pencil layer");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
-
RNA_def_property_int_funcs(prop,
"rna_GPencil_active_layer_index_get",
"rna_GPencil_active_layer_index_set",
"rna_GPencil_active_layer_index_range");
RNA_def_property_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
}
static void rna_def_gpencil_palettecolor(BlenderRNA *brna)
@@ -1443,7 +1470,7 @@ static void rna_def_gpencil_palettecolor(BlenderRNA *brna)
prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_ONIONSKIN);
RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0);
- RNA_def_property_ui_text(prop, "Ghost", "Display the color in onion skinning");
+ RNA_def_property_ui_text(prop, "Show in Ghosts", "Display strokes using this color when showing onion skins");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Draw Style */
@@ -1495,8 +1522,8 @@ static void rna_def_gpencil_palettecolors_api(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Remove a color from the palette");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The color 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPencilPaletteColor");
@@ -1556,8 +1583,8 @@ static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_GPencil_palette_new");
RNA_def_function_ui_description(func, "Add a new grease pencil palette");
parm = RNA_def_string(func, "name", "GPencilPalette", MAX_NAME, "Name", "Name of the palette");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_boolean(func, "set_active", 0, "Set Active", "Activate the newly created palette");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_boolean(func, "set_active", true, "Set Active", "Activate the newly created palette");
parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The newly created palette");
RNA_def_function_return(func, parm);
@@ -1565,8 +1592,8 @@ static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a grease pencil palette");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPencilPalette");
diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c
index 47bee589615..aa02a3c159d 100644
--- a/source/blender/makesrna/intern/rna_group.c
+++ b/source/blender/makesrna/intern/rna_group.c
@@ -95,7 +95,7 @@ static void rna_def_group_objects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add this object to a group");
/* object to add */
parm = RNA_def_pointer(func, "object", "Object", "", "Object to add");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* remove object */
func = RNA_def_function(srna, "unlink", "rna_Group_objects_unlink");
@@ -103,7 +103,7 @@ static void rna_def_group_objects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
/* object to remove */
parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index f65aa90ea71..5ca7e624d88 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -192,6 +192,8 @@ static char *rna_ImageUser_path(PointerRNA *ptr)
{
return rna_Node_ImageUser_path(ptr);
}
+ default:
+ break;
}
}
@@ -871,7 +873,7 @@ static void rna_def_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "has_data", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_Image_has_data_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Has data", "True if this image has data");
+ RNA_def_property_ui_text(prop, "Has Data", "True if the image data is loaded into memory");
prop = RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop, "rna_Image_depth_get", NULL, NULL);
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 6530e0938f6..61f1edc0af5 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -67,7 +67,7 @@
static void rna_ImagePackedFile_save(ImagePackedFile *imapf, ReportList *reports)
{
if (writePackedFile(reports, imapf->filepath, imapf->packedfile, 0) != RET_OK) {
- BKE_reportf(reports, RPT_ERROR, "Image could not save packed file to '%s'",
+ BKE_reportf(reports, RPT_ERROR, "Could not save packed file to disk as '%s'",
imapf->filepath);
}
}
@@ -291,7 +291,7 @@ static void rna_Image_filepath_from_user(Image *image, ImageUser *image_user, ch
static void rna_Image_buffers_free(Image *image)
{
- BKE_image_free_buffers(image);
+ BKE_image_free_buffers_ex(image, true);
}
#else
@@ -314,7 +314,7 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_ui_description(func, "Save image to a specific path using a scenes render settings");
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
parm = RNA_def_string_file_path(func, "filepath", NULL, 0, "", "Save path");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_pointer(func, "scene", "Scene", "", "Scene to take image parameters from");
func = RNA_def_function(srna, "save", "rna_Image_save");
@@ -346,9 +346,9 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_ui_description(func, "Scale the image in pixels");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_int(func, "width", 1, 1, 10000, "", "Width", 1, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "height", 1, 1, 10000, "", "Height", 1, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "gl_touch", "rna_Image_gl_touch");
RNA_def_function_ui_description(func, "Delay the image from being cleaned from the cache due inactivity");
@@ -372,7 +372,6 @@ void RNA_api_image(StructRNA *srna)
"The texture minifying function", -INT_MAX, INT_MAX);
RNA_def_int(func, "mag", GL_LINEAR, -INT_MAX, INT_MAX, "Magnification",
"The texture magnification function", -INT_MAX, INT_MAX);
-
/* return value */
parm = RNA_def_int(func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
RNA_def_function_return(func, parm);
@@ -386,7 +385,7 @@ void RNA_api_image(StructRNA *srna)
RNA_def_pointer(func, "image_user", "ImageUser", "", "Image user of the image to get filepath for");
parm = RNA_def_string_file_path(func, "filepath", NULL, FILE_MAX, "File Path",
"The resulting filepath from the image and it's user");
- RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
func = RNA_def_function(srna, "buffers_free", "rna_Image_buffers_free");
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 76455adbc78..dfd5af788f6 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -344,6 +344,7 @@ extern IntPropertyRNA rna_PropertyGroupItem_int_array;
extern FloatPropertyRNA rna_PropertyGroupItem_float;
extern FloatPropertyRNA rna_PropertyGroupItem_float_array;
extern PointerPropertyRNA rna_PropertyGroupItem_group;
+extern PointerPropertyRNA rna_PropertyGroupItem_id;
extern CollectionPropertyRNA rna_PropertyGroupItem_collection;
extern CollectionPropertyRNA rna_PropertyGroupItem_idp_array;
extern FloatPropertyRNA rna_PropertyGroupItem_double;
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 04b85b8997e..a470c807091 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -94,6 +94,7 @@ typedef PointerRNA (*PropPointerGetFunc)(struct PointerRNA *ptr);
typedef StructRNA *(*PropPointerTypeFunc)(struct PointerRNA *ptr);
typedef void (*PropPointerSetFunc)(struct PointerRNA *ptr, const PointerRNA value);
typedef int (*PropPointerPollFunc)(struct PointerRNA *ptr, const PointerRNA value);
+typedef int (*PropPointerPollFuncPy)(struct PointerRNA *ptr, const PointerRNA value, const PropertyRNA *prop);
typedef void (*PropCollectionBeginFunc)(struct CollectionPropertyIterator *iter, struct PointerRNA *ptr);
typedef void (*PropCollectionNextFunc)(struct CollectionPropertyIterator *iter);
typedef void (*PropCollectionEndFunc)(struct CollectionPropertyIterator *iter);
@@ -162,6 +163,10 @@ struct PropertyRNA {
const char *identifier;
/* various options */
int flag;
+ /* Function parameters flags. */
+ short flag_parameter;
+ /* Internal ("private") flags. */
+ short flag_internal;
/* user readable name */
const char *name;
@@ -183,7 +188,7 @@ struct PropertyRNA {
/* array lengths lengths for all dimensions (when arraydimension > 0) */
unsigned int arraylength[RNA_MAX_ARRAY_DIMENSION];
unsigned int totarraylength;
-
+
/* callback for updates on change */
UpdateFunc update;
int noteflag;
@@ -209,6 +214,15 @@ struct PropertyRNA {
void *py_data;
};
+/* internal flags WARNING! 16bits only! */
+typedef enum PropertyFlagIntern {
+ PROP_INTERN_BUILTIN = (1 << 0),
+ PROP_INTERN_RUNTIME = (1 << 1),
+ PROP_INTERN_RAW_ACCESS = (1 << 2),
+ PROP_INTERN_RAW_ARRAY = (1 << 3),
+ PROP_INTERN_FREE_POINTERS = (1 << 4),
+} PropertyFlagIntern;
+
/* Property Types */
typedef struct BoolPropertyRNA {
@@ -347,7 +361,7 @@ struct StructRNA {
* which is useful for subclassing RNA */
void *py_type;
void *blender_type;
-
+
/* various options */
int flag;
@@ -359,7 +373,7 @@ struct StructRNA {
const char *translation_context;
/* icon ID */
int icon;
-
+
/* property that defines the name */
PropertyRNA *nameproperty;
@@ -399,6 +413,11 @@ struct StructRNA {
struct BlenderRNA {
ListBase structs;
+ /* A map of structs: {StructRNA.identifier -> StructRNA}
+ * These are ensured to have unique names (with STRUCT_PUBLIC_NAMESPACE enabled). */
+ struct GHash *structs_map;
+ /* Needed because types with an empty identifier aren't included in 'structs_map'. */
+ unsigned int structs_len;
};
#define CONTAINER_RNA_ID(cont) (*(const char **)(((ContainerRNA *)(cont))+1))
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index f20e8fb8ed4..b960890457b 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -33,6 +33,7 @@
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -177,6 +178,8 @@ static Mesh *rna_KeyBlock_normals_get_mesh(PointerRNA *ptr, ID *id)
return ob->data;
}
}
+ default:
+ break;
}
}
@@ -748,7 +751,7 @@ static void rna_def_keyblock(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Compute local space vertices' normals for this shape key");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT);
RNA_def_property_multi_array(parm, 2, NULL);
RNA_def_property_range(parm, -1.0f, 1.0f);
RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_vert_len");
@@ -757,7 +760,7 @@ static void rna_def_keyblock(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Compute local space faces' normals for this shape key");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT);
RNA_def_property_multi_array(parm, 2, NULL);
RNA_def_property_range(parm, -1.0f, 1.0f);
RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_poly_len");
@@ -766,7 +769,7 @@ static void rna_def_keyblock(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Compute local space face corners' normals for this shape key");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT);
RNA_def_property_multi_array(parm, 2, NULL);
RNA_def_property_range(parm, -1.0f, 1.0f);
RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_loop_len");
diff --git a/source/blender/makesrna/intern/rna_lattice_api.c b/source/blender/makesrna/intern/rna_lattice_api.c
index ed0489db1a2..2ea59d31262 100644
--- a/source/blender/makesrna/intern/rna_lattice_api.c
+++ b/source/blender/makesrna/intern/rna_lattice_api.c
@@ -57,7 +57,7 @@ void RNA_api_lattice(StructRNA *srna)
func = RNA_def_function(srna, "transform", "rna_Lattice_transform");
RNA_def_function_ui_description(func, "Transform lattice by a matrix");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
}
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index 9b28009d161..a163d9764c1 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -27,6 +27,9 @@
#include <stdio.h>
#include <stdlib.h>
+#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
+
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -1447,9 +1450,9 @@ static void rna_def_freestyle_color_modifiers(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Add a color modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "ColorModifier", 0, "", "New name for the color modifier (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_linestyle_color_modifier_type_items, 0, "", "Color modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleColorModifier", "", "Newly added color modifier");
RNA_def_function_return(func, parm);
@@ -1457,8 +1460,8 @@ static void rna_def_freestyle_color_modifiers(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Remove a color modifier from line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "modifier", "LineStyleColorModifier", "", "Color modifier 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_freestyle_alpha_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1476,9 +1479,9 @@ static void rna_def_freestyle_alpha_modifiers(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Add a alpha modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "AlphaModifier", 0, "", "New name for the alpha modifier (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_linestyle_alpha_modifier_type_items, 0, "", "Alpha modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleAlphaModifier", "", "Newly added alpha modifier");
RNA_def_function_return(func, parm);
@@ -1486,8 +1489,8 @@ static void rna_def_freestyle_alpha_modifiers(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Remove a alpha modifier from line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "modifier", "LineStyleAlphaModifier", "", "Alpha modifier 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1505,10 +1508,10 @@ static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA
RNA_def_function_ui_description(func, "Add a thickness modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "ThicknessModifier", 0, "", "New name for the thickness modifier (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_linestyle_thickness_modifier_type_items, 0,
"", "Thickness modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Newly added thickness modifier");
RNA_def_function_return(func, parm);
@@ -1516,8 +1519,8 @@ static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA
RNA_def_function_ui_description(func, "Remove a thickness modifier from line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Thickness modifier 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1535,10 +1538,10 @@ static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA *
RNA_def_function_ui_description(func, "Add a geometry modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "GeometryModifier", 0, "", "New name for the geometry modifier (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_linestyle_geometry_modifier_type_items, 0,
"", "Geometry modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Newly added geometry modifier");
RNA_def_function_return(func, parm);
@@ -1546,8 +1549,8 @@ static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA *
RNA_def_function_ui_description(func, "Remove a geometry modifier from line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Geometry modifier 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_linestyle(BlenderRNA *brna)
@@ -1617,6 +1620,7 @@ static void rna_def_linestyle(BlenderRNA *brna)
prop = RNA_def_property(srna, "panel", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "panel");
RNA_def_property_enum_items(prop, panel_items);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Panel", "Select the property panel to be shown");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 594c1752328..871f50e992e 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -116,7 +116,15 @@
#endif
-static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink)
+static void rna_idname_validate(const char *name, char *r_name)
+{
+ BLI_strncpy(r_name, name, MAX_ID_NAME - 2);
+ BLI_utf8_invalid_strip(r_name, strlen(r_name));
+}
+
+
+static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr,
+ int do_unlink, int do_id_user, int do_ui_user)
{
ID *id = id_ptr->data;
if (do_unlink) {
@@ -124,7 +132,7 @@ static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_
RNA_POINTER_INVALIDATE(id_ptr);
}
else if (ID_REAL_USERS(id) <= 0) {
- BKE_libblock_free(bmain, id);
+ BKE_libblock_free_ex(bmain, id, do_id_user, do_ui_user);
RNA_POINTER_INVALIDATE(id_ptr);
}
else {
@@ -137,14 +145,20 @@ static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_
static Camera *rna_Main_cameras_new(Main *bmain, const char *name)
{
- ID *id = BKE_camera_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ ID *id = BKE_camera_add(bmain, safe_name);
id_us_min(id);
return (Camera *)id;
}
static Scene *rna_Main_scenes_new(Main *bmain, const char *name)
{
- return BKE_scene_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ return BKE_scene_add(bmain, safe_name);
}
static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr, int do_unlink)
{
@@ -171,7 +185,7 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports
}
}
- rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink);
+ rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink, true, true);
}
else {
BKE_reportf(reports, RPT_ERROR, "Scene '%s' is the last, cannot be removed", scene->id.name + 2);
@@ -180,6 +194,9 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports
static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char *name, ID *data)
{
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
Object *ob;
int type = OB_EMPTY;
if (data) {
@@ -223,7 +240,7 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
id_us_plus(data);
}
- ob = BKE_object_add_only_object(bmain, type, name);
+ ob = BKE_object_add_only_object(bmain, type, safe_name);
id_us_min(&ob->id);
ob->data = data;
@@ -234,7 +251,10 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
static Material *rna_Main_materials_new(Main *bmain, const char *name)
{
- ID *id = (ID *)BKE_material_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ ID *id = (ID *)BKE_material_add(bmain, safe_name);
id_us_min(id);
return (Material *)id;
}
@@ -245,20 +265,27 @@ static EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), Point
}
static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, int type)
{
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
bNodeTreeType *typeinfo = rna_node_tree_type_from_enum(type);
if (typeinfo) {
- bNodeTree *ntree = ntreeAddTree(bmain, name, typeinfo->idname);
+ bNodeTree *ntree = ntreeAddTree(bmain, safe_name, typeinfo->idname);
id_us_min(&ntree->id);
return ntree;
}
- else
+ else {
return NULL;
+ }
}
static Mesh *rna_Main_meshes_new(Main *bmain, const char *name)
{
- Mesh *me = BKE_mesh_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Mesh *me = BKE_mesh_add(bmain, safe_name);
id_us_min(&me->id);
return me;
}
@@ -286,7 +313,10 @@ Mesh *rna_Main_meshes_new_from_object(
static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type)
{
- Lamp *lamp = BKE_lamp_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Lamp *lamp = BKE_lamp_add(bmain, safe_name);
lamp->type = type;
id_us_min(&lamp->id);
return lamp;
@@ -294,8 +324,11 @@ static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type)
static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d)
{
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
float color[4] = {0.0, 0.0, 0.0, 1.0};
- Image *image = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d);
+ Image *image = BKE_image_add_generated(bmain, width, height, safe_name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d);
id_us_min(&image->id);
return image;
}
@@ -322,21 +355,30 @@ static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char
static Lattice *rna_Main_lattices_new(Main *bmain, const char *name)
{
- Lattice *lt = BKE_lattice_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Lattice *lt = BKE_lattice_add(bmain, safe_name);
id_us_min(&lt->id);
return lt;
}
static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type)
{
- Curve *cu = BKE_curve_add(bmain, name, type);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Curve *cu = BKE_curve_add(bmain, safe_name, type);
id_us_min(&cu->id);
return cu;
}
static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name)
{
- MetaBall *mb = BKE_mball_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ MetaBall *mb = BKE_mball_add(bmain, safe_name);
id_us_min(&mb->id);
return mb;
}
@@ -364,7 +406,10 @@ static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *
static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
{
- Tex *tex = BKE_texture_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Tex *tex = BKE_texture_add(bmain, safe_name);
BKE_texture_type_set(tex, type);
id_us_min(&tex->id);
return tex;
@@ -372,26 +417,38 @@ static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode)
{
- Brush *brush = BKE_brush_add(bmain, name, mode);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Brush *brush = BKE_brush_add(bmain, safe_name, mode);
id_us_min(&brush->id);
return brush;
}
static World *rna_Main_worlds_new(Main *bmain, const char *name)
{
- World *world = add_world(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ World *world = add_world(bmain, safe_name);
id_us_min(&world->id);
return world;
}
static Group *rna_Main_groups_new(Main *bmain, const char *name)
{
- return BKE_group_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ return BKE_group_add(bmain, safe_name);
}
static Speaker *rna_Main_speakers_new(Main *bmain, const char *name)
{
- Speaker *speaker = BKE_speaker_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Speaker *speaker = BKE_speaker_add(bmain, safe_name);
id_us_min(&speaker->id);
return speaker;
}
@@ -413,7 +470,10 @@ static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_exi
static Text *rna_Main_texts_new(Main *bmain, const char *name)
{
- return BKE_text_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ return BKE_text_add(bmain, safe_name);
}
static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *filepath, int is_internal)
@@ -432,28 +492,40 @@ static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *f
static bArmature *rna_Main_armatures_new(Main *bmain, const char *name)
{
- bArmature *arm = BKE_armature_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ bArmature *arm = BKE_armature_add(bmain, safe_name);
id_us_min(&arm->id);
return arm;
}
static bAction *rna_Main_actions_new(Main *bmain, const char *name)
{
- bAction *act = add_empty_action(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ bAction *act = add_empty_action(bmain, safe_name);
id_fake_user_clear(&act->id);
return act;
}
static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name)
{
- ParticleSettings *part = psys_new_settings(name, bmain);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ ParticleSettings *part = psys_new_settings(safe_name, bmain);
id_us_min(&part->id);
return part;
}
static Palette *rna_Main_palettes_new(Main *bmain, const char *name)
{
- Palette *palette = BKE_palette_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Palette *palette = BKE_palette_add(bmain, safe_name);
id_us_min(&palette->id);
return (Palette *)palette;
}
@@ -481,16 +553,18 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons
static Mask *rna_Main_mask_new(Main *bmain, const char *name)
{
- Mask *mask;
-
- mask = BKE_mask_new(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
- return mask;
+ return BKE_mask_new(bmain, safe_name);
}
static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name)
{
- FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, safe_name);
id_us_min(&linestyle->id);
return linestyle;
}
@@ -553,7 +627,7 @@ void RNA_api_main(StructRNA *UNUSED(srna))
func = RNA_def_function(srna, "add_image", "rna_Main_add_image");
RNA_def_function_ui_description(func, "Add a new image");
parm = RNA_def_string_file_path(func, "filepath", NULL, 0, "", "File path to load image from");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "image", "Image", "", "New image");
RNA_def_function_return(func, parm);
#endif
@@ -574,7 +648,7 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_cameras_new");
RNA_def_function_ui_description(func, "Add a new camera to the main database");
parm = RNA_def_string(func, "name", "Camera", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera data-block");
RNA_def_function_return(func, parm);
@@ -583,15 +657,19 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this camera before deleting it "
"(WARNING: will also delete objects instancing that camera data)");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this camera");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this camera");
func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -613,7 +691,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_scenes_new");
RNA_def_function_ui_description(func, "Add a new scene to the main database");
parm = RNA_def_string(func, "name", "Scene", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "scene", "Scene", "", "New scene data-block");
RNA_def_function_return(func, parm);
@@ -622,13 +700,13 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a scene from the current blendfile");
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "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", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -651,9 +729,9 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new object to the main database");
parm = RNA_def_string(func, "name", "Object", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "object_data", "ID", "", "Object data or None for an empty object");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "object", "Object", "", "New object data-block");
@@ -663,13 +741,17 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this object before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this object");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this object");
func = RNA_def_function(srna, "tag", "rna_Main_objects_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -691,7 +773,7 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_materials_new");
RNA_def_function_ui_description(func, "Add a new material to the main database");
parm = RNA_def_string(func, "name", "Material", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block");
RNA_def_function_return(func, parm);
@@ -700,13 +782,17 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this material before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this material");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this material");
func = RNA_def_function(srna, "tag", "rna_Main_materials_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -732,10 +818,10 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_nodetree_new");
RNA_def_function_ui_description(func, "Add a new node tree to the main database");
parm = RNA_def_string(func, "name", "NodeGroup", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", dummy_items, 0, "Type", "The type of node_group to add");
RNA_def_property_enum_funcs(parm, NULL, NULL, "rna_Main_nodetree_type_itemf");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree data-block");
RNA_def_function_return(func, parm);
@@ -744,13 +830,17 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this node tree before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this node tree");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this node tree");
func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -777,7 +867,7 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_meshes_new");
RNA_def_function_ui_description(func, "Add a new mesh to the main database");
parm = RNA_def_string(func, "name", "Mesh", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "mesh", "Mesh", "", "New mesh data-block");
RNA_def_function_return(func, parm);
@@ -786,13 +876,13 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a new mesh created from object with modifiers applied");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "object", "Object", "", "Object to create mesh from");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "calc_tessface", true, "Calculate Tessellation", "Calculate tessellation faces");
RNA_def_boolean(func, "calc_undeformed", false, "Calculate Undeformed", "Calculate undeformed vertex coordinates");
parm = RNA_def_pointer(func, "mesh", "Mesh", "",
@@ -803,15 +893,19 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this mesh before deleting it "
"(WARNING: will also delete objects instancing that mesh data)");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this mesh data");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this mesh data");
func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -832,9 +926,9 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_lamps_new");
RNA_def_function_ui_description(func, "Add a new lamp to the main database");
parm = RNA_def_string(func, "name", "Lamp", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_lamp_type_items, 0, "Type", "The type of texture to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block");
RNA_def_function_return(func, parm);
@@ -843,15 +937,19 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this lamp before deleting it "
"(WARNING: will also delete objects instancing that lamp data)");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this lamp data");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this lamp data");
func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -872,7 +970,7 @@ void RNA_def_main_libraries(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_libraries_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -893,7 +991,7 @@ void RNA_def_main_screens(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_screens_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -914,7 +1012,7 @@ void RNA_def_main_window_managers(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_window_managers_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -935,11 +1033,11 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_images_new");
RNA_def_function_ui_description(func, "Add a new image to the main database");
parm = RNA_def_string(func, "name", "Image", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "width", 1024, 1, INT_MAX, "", "Width of the image", 1, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "height", 1024, 1, INT_MAX, "", "Height of the image", 1, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "alpha", 0, "Alpha", "Use alpha channel");
RNA_def_boolean(func, "float_buffer", 0, "Float Buffer", "Create an image with floating point color");
RNA_def_boolean(func, "stereo3d", 0, "Stereo 3D", "Create left and right views");
@@ -951,7 +1049,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Load a new image into the main database");
parm = RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the file to load");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block");
@@ -961,13 +1059,17 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this image before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this image");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this image");
func = RNA_def_function(srna, "tag", "rna_Main_images_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -989,7 +1091,7 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_lattices_new");
RNA_def_function_ui_description(func, "Add a new lattice to the main database");
parm = RNA_def_string(func, "name", "Lattice", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices data-block");
RNA_def_function_return(func, parm);
@@ -998,15 +1100,19 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this lattice before deleting it "
"(WARNING: will also delete objects instancing that lattice data)");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this lattice data");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this lattice data");
func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1027,9 +1133,9 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_curves_new");
RNA_def_function_ui_description(func, "Add a new curve to the main database");
parm = RNA_def_string(func, "name", "Curve", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_object_type_curve_items, 0, "Type", "The type of curve to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve data-block");
RNA_def_function_return(func, parm);
@@ -1038,15 +1144,19 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this curve before deleting it "
"(WARNING: will also delete objects instancing that curve data)");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this curve data");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this curve data");
func = RNA_def_function(srna, "tag", "rna_Main_curves_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1067,7 +1177,7 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_metaballs_new");
RNA_def_function_ui_description(func, "Add a new metaball to the main database");
parm = RNA_def_string(func, "name", "MetaBall", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball data-block");
RNA_def_function_return(func, parm);
@@ -1076,15 +1186,19 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this metaball before deleting it "
"(WARNING: will also delete objects instancing that metaball data)");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this metaball data");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this metaball data");
func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1106,7 +1220,7 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Load a new font into the main database");
parm = RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the font to load");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font data-block");
@@ -1116,13 +1230,17 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this font before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this font");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this font");
func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1143,9 +1261,9 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_textures_new");
RNA_def_function_ui_description(func, "Add a new texture to the main database");
parm = RNA_def_string(func, "name", "Texture", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_texture_type_items, 0, "Type", "The type of texture to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture data-block");
RNA_def_function_return(func, parm);
@@ -1154,13 +1272,17 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this texture before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this texture");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this texture");
func = RNA_def_function(srna, "tag", "rna_Main_textures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1181,7 +1303,7 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_brushes_new");
RNA_def_function_ui_description(func, "Add a new brush to the main database");
parm = RNA_def_string(func, "name", "Brush", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "mode", rna_enum_object_mode_items, OB_MODE_TEXTURE_PAINT, "", "Paint Mode for the new brush");
/* return type */
parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush data-block");
@@ -1191,13 +1313,17 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this brush before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this brush");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this brush");
func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1219,7 +1345,7 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_worlds_new");
RNA_def_function_ui_description(func, "Add a new world to the main database");
parm = RNA_def_string(func, "name", "World", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "world", "World", "", "New world data-block");
RNA_def_function_return(func, parm);
@@ -1228,13 +1354,17 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this world before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this world");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this world");
func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1256,7 +1386,7 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_groups_new");
RNA_def_function_ui_description(func, "Add a new group to the main database");
parm = RNA_def_string(func, "name", "Group", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block");
RNA_def_function_return(func, parm);
@@ -1265,13 +1395,17 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this group before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this group");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this group");
func = RNA_def_function(srna, "tag", "rna_Main_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1293,7 +1427,7 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_speakers_new");
RNA_def_function_ui_description(func, "Add a new speaker to the main database");
parm = RNA_def_string(func, "name", "Speaker", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker data-block");
RNA_def_function_return(func, parm);
@@ -1302,15 +1436,19 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this speaker before deleting it "
"(WARNING: will also delete objects instancing that speaker data)");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this speaker data");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this speaker data");
func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1332,7 +1470,7 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_texts_new");
RNA_def_function_ui_description(func, "Add a new text to the main database");
parm = RNA_def_string(func, "name", "Text", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block");
RNA_def_function_return(func, parm);
@@ -1341,16 +1479,20 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this text before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this text");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this text");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_texts_load");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new text to the main database from a file");
parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "internal", 0, "Make internal", "Make text file internal after loading");
/* return type */
parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block");
@@ -1358,7 +1500,7 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_texts_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1381,7 +1523,7 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "load", "rna_Main_sounds_load");
RNA_def_function_ui_description(func, "Add a new sound to the main database from a file");
parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
parm = RNA_def_pointer(func, "sound", "Sound", "", "New text data-block");
@@ -1391,13 +1533,17 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this sound before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this sound");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this sound");
func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1419,7 +1565,7 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_armatures_new");
RNA_def_function_ui_description(func, "Add a new armature to the main database");
parm = RNA_def_string(func, "name", "Armature", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature data-block");
RNA_def_function_return(func, parm);
@@ -1428,15 +1574,19 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this armature before deleting it "
"(WARNING: will also delete objects instancing that armature data)");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this armature data");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this armature data");
func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1457,7 +1607,7 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_actions_new");
RNA_def_function_ui_description(func, "Add a new action to the main database");
parm = RNA_def_string(func, "name", "Action", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "action", "Action", "", "New action data-block");
RNA_def_function_return(func, parm);
@@ -1466,13 +1616,17 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this action before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this action");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this action");
func = RNA_def_function(srna, "tag", "rna_Main_actions_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1493,7 +1647,7 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_particles_new");
RNA_def_function_ui_description(func, "Add a new particle settings instance to the main database");
parm = RNA_def_string(func, "name", "ParticleSettings", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "New particle settings data-block");
RNA_def_function_return(func, parm);
@@ -1502,13 +1656,17 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of those particle settings before deleting them");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this particle settings");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this particle settings");
func = RNA_def_function(srna, "tag", "rna_Main_particles_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1529,7 +1687,7 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_palettes_new");
RNA_def_function_ui_description(func, "Add a new palette to the main database");
parm = RNA_def_string(func, "name", "Palette", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette data-block");
RNA_def_function_return(func, parm);
@@ -1538,13 +1696,17 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this palette before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this palette");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this palette");
func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1552,31 +1714,41 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
}
void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop)
{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+ PropertyRNA *prop;
+
RNA_def_property_srna(cprop, "BlendDataCacheFiles");
- StructRNA *srna = RNA_def_struct(brna, "BlendDataCacheFiles", NULL);
+ srna = RNA_def_struct(brna, "BlendDataCacheFiles", NULL);
RNA_def_struct_sdna(srna, "Main");
RNA_def_struct_ui_text(srna, "Main Cache Files", "Collection of cache files");
- FunctionRNA *func = RNA_def_function(srna, "tag", "rna_Main_cachefiles_tag");
- PropertyRNA *parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ func = RNA_def_function(srna, "tag", "rna_Main_cachefiles_tag");
+ parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- PropertyRNA *prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Main_cachefiles_is_updated_get", NULL);
}
void RNA_def_main_paintcurves(BlenderRNA *brna, PropertyRNA *cprop)
{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+ PropertyRNA *prop;
+
RNA_def_property_srna(cprop, "BlendDataPaintCurves");
- StructRNA *srna = RNA_def_struct(brna, "BlendDataPaintCurves", NULL);
+ srna = RNA_def_struct(brna, "BlendDataPaintCurves", NULL);
RNA_def_struct_sdna(srna, "Main");
RNA_def_struct_ui_text(srna, "Main Paint Curves", "Collection of paint curves");
- FunctionRNA *func = RNA_def_function(srna, "tag", "rna_Main_paintcurves_tag");
- PropertyRNA *parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ func = RNA_def_function(srna, "tag", "rna_Main_paintcurves_tag");
+ parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- PropertyRNA *prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Main_paintcurves_is_updated_get", NULL);
}
@@ -1594,12 +1766,12 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_gpencil_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "new", "BKE_gpencil_data_addnew");
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_string(func, "name", "GreasePencil", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil data-block");
RNA_def_function_return(func, parm);
@@ -1608,9 +1780,13 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this grease pencil before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this grease pencil");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this grease pencil");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1631,15 +1807,19 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_movieclips_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this movie clip before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this movie clip");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this movie clip");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_movieclip_load");
@@ -1649,7 +1829,7 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
"(while ``check_existing`` is disabled for consistency with other load functions, "
"behavior with multiple movie-clips using the same file may incorrectly generate proxies)");
parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
parm = RNA_def_pointer(func, "clip", "MovieClip", "", "New movie clip data-block");
@@ -1674,7 +1854,7 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_masks_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* new func */
func = RNA_def_function(srna, "new", "rna_Main_mask_new");
@@ -1689,9 +1869,13 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mask before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this mask");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this mask");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1712,12 +1896,12 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_linestyle_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "new", "rna_Main_linestyles_new");
RNA_def_function_ui_description(func, "Add a new line style instance to the main database");
parm = RNA_def_string(func, "name", "FreestyleLineStyle", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style data-block");
RNA_def_function_return(func, parm);
@@ -1726,9 +1910,13 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
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 | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this line style before deleting it");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this line style");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this line style");
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_mask.c b/source/blender/makesrna/intern/rna_mask.c
index faf36d28ff9..24dfff89832 100644
--- a/source/blender/makesrna/intern/rna_mask.c
+++ b/source/blender/makesrna/intern/rna_mask.c
@@ -778,8 +778,8 @@ static void rna_def_mask_splines(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Remove a spline from a layer");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "spline", "MaskSpline", "", "The spline 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* active spline */
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
@@ -818,8 +818,8 @@ static void rna_def_maskSplinePoints(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Remove a point from a spline");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "point", "MaskSplinePoint", "", "The point 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_maskSpline(BlenderRNA *brna)
@@ -1014,8 +1014,8 @@ static void rna_def_masklayers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove layer from this mask");
parm = RNA_def_pointer(func, "layer", "MaskLayer", "", "Shape to be removed");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* clear all layers */
func = RNA_def_function(srna, "clear", "rna_Mask_layers_clear");
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 752f406264a..b293f20dd95 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -2163,14 +2163,14 @@ static void rna_def_texture_slots(BlenderRNA *brna, PropertyRNA *cprop, const ch
func = RNA_def_function(srna, "create", "rna_mtex_texture_slots_create");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Slot index to initialize", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "mtex", structname, "", "The newly initialized mtex");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "clear", "rna_mtex_texture_slots_clear");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Slot index to clear", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void rna_def_mtex_common(BlenderRNA *brna, StructRNA *srna, const char *begin,
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 7c66f43fe00..650caf20093 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -46,6 +46,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_types.h"
+#include "RNA_enum_types.h"
#include "rna_internal.h"
@@ -303,7 +304,7 @@ static float rna_MeshVertex_bevel_weight_get(PointerRNA *ptr)
static void rna_MeshVertex_bevel_weight_set(PointerRNA *ptr, float value)
{
MVert *mvert = (MVert *)ptr->data;
- mvert->bweight = (char)(CLAMPIS(value * 255.0f, 0, 255));
+ mvert->bweight = round_fl_to_uchar_clamp(value * 255.0f);
}
static float rna_MEdge_bevel_weight_get(PointerRNA *ptr)
@@ -315,7 +316,7 @@ static float rna_MEdge_bevel_weight_get(PointerRNA *ptr)
static void rna_MEdge_bevel_weight_set(PointerRNA *ptr, float value)
{
MEdge *medge = (MEdge *)ptr->data;
- medge->bweight = (char)(CLAMPIS(value * 255.0f, 0, 255));
+ medge->bweight = round_fl_to_uchar_clamp(value * 255.0f);
}
static float rna_MEdge_crease_get(PointerRNA *ptr)
@@ -327,7 +328,7 @@ static float rna_MEdge_crease_get(PointerRNA *ptr)
static void rna_MEdge_crease_set(PointerRNA *ptr, float value)
{
MEdge *medge = (MEdge *)ptr->data;
- medge->crease = (char)(CLAMPIS(value * 255.0f, 0, 255));
+ medge->crease = round_fl_to_uchar_clamp(value * 255.0f);
}
static void rna_MeshLoop_normal_get(PointerRNA *ptr, float *values)
@@ -585,15 +586,17 @@ static void rna_MeshColor_color1_set(PointerRNA *ptr, const float *values)
{
MCol *mcol = (MCol *)ptr->data;
- (&mcol[0].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255));
- (&mcol[0].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255));
- (&mcol[0].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255));
+ (&mcol[0].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f);
+ (&mcol[0].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f);
+ (&mcol[0].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f);
+ (&mcol[0].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f);
}
static void rna_MeshColor_color2_get(PointerRNA *ptr, float *values)
{
MCol *mcol = (MCol *)ptr->data;
+ values[3] = (&mcol[1].r)[3] / 255.0f;
values[2] = (&mcol[1].r)[0] / 255.0f;
values[1] = (&mcol[1].r)[1] / 255.0f;
values[0] = (&mcol[1].r)[2] / 255.0f;
@@ -603,15 +606,17 @@ static void rna_MeshColor_color2_set(PointerRNA *ptr, const float *values)
{
MCol *mcol = (MCol *)ptr->data;
- (&mcol[1].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255));
- (&mcol[1].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255));
- (&mcol[1].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255));
+ (&mcol[1].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f);
+ (&mcol[1].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f);
+ (&mcol[1].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f);
+ (&mcol[1].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f);
}
static void rna_MeshColor_color3_get(PointerRNA *ptr, float *values)
{
MCol *mcol = (MCol *)ptr->data;
+ values[3] = (&mcol[2].r)[3] / 255.0f;
values[2] = (&mcol[2].r)[0] / 255.0f;
values[1] = (&mcol[2].r)[1] / 255.0f;
values[0] = (&mcol[2].r)[2] / 255.0f;
@@ -621,9 +626,10 @@ static void rna_MeshColor_color3_set(PointerRNA *ptr, const float *values)
{
MCol *mcol = (MCol *)ptr->data;
- (&mcol[2].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255));
- (&mcol[2].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255));
- (&mcol[2].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255));
+ (&mcol[2].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f);
+ (&mcol[2].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f);
+ (&mcol[2].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f);
+ (&mcol[2].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f);
}
static void rna_MeshColor_color4_get(PointerRNA *ptr, float *values)
@@ -633,15 +639,17 @@ static void rna_MeshColor_color4_get(PointerRNA *ptr, float *values)
values[2] = (&mcol[3].r)[0] / 255.0f;
values[1] = (&mcol[3].r)[1] / 255.0f;
values[0] = (&mcol[3].r)[2] / 255.0f;
+ values[3] = (&mcol[3].r)[3] / 255.0f;
}
static void rna_MeshColor_color4_set(PointerRNA *ptr, const float *values)
{
MCol *mcol = (MCol *)ptr->data;
- (&mcol[3].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255));
- (&mcol[3].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255));
- (&mcol[3].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255));
+ (&mcol[3].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f);
+ (&mcol[3].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f);
+ (&mcol[3].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f);
+ (&mcol[3].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f);
}
static void rna_MeshLoopColor_color_get(PointerRNA *ptr, float *values)
@@ -651,15 +659,17 @@ static void rna_MeshLoopColor_color_get(PointerRNA *ptr, float *values)
values[0] = (&mcol->r)[0] / 255.0f;
values[1] = (&mcol->r)[1] / 255.0f;
values[2] = (&mcol->r)[2] / 255.0f;
+ values[3] = (&mcol->r)[3] / 255.0f;
}
static void rna_MeshLoopColor_color_set(PointerRNA *ptr, const float *values)
{
MLoopCol *mcol = (MLoopCol *)ptr->data;
- (&mcol->r)[0] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255));
- (&mcol->r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255));
- (&mcol->r)[2] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255));
+ (&mcol->r)[0] = round_fl_to_uchar_clamp(values[0] * 255.0f);
+ (&mcol->r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f);
+ (&mcol->r)[2] = round_fl_to_uchar_clamp(values[2] * 255.0f);
+ (&mcol->r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f);
}
static int rna_Mesh_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info))
@@ -1962,7 +1972,7 @@ static void rna_def_medge(BlenderRNA *brna)
prop = RNA_def_property(srna, "crease", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_MEdge_crease_get", "rna_MEdge_crease_set", NULL);
- RNA_def_property_ui_text(prop, "Crease", "Weight used by the Subsurf modifier for creasing");
+ RNA_def_property_ui_text(prop, "Crease", "Weight used by the Subdivision Surface modifier for creasing");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "bevel_weight", PROP_FLOAT, PROP_NONE);
@@ -1987,7 +1997,7 @@ static void rna_def_medge(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_edge_sharp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SHARP);
- RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the EdgeSplit modifier");
+ RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the Edge Split modifier");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "is_loose", PROP_BOOLEAN, PROP_NONE);
@@ -2229,7 +2239,6 @@ static void rna_def_mpolygon(BlenderRNA *brna)
func = RNA_def_function(srna, "flip", "rna_MeshPolygon_flip");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Invert winding of this polygon (flip its normal)");
-
}
/* mesh.loop_uvs */
@@ -2504,28 +2513,28 @@ static void rna_def_mcol(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_MeshColor_path");
prop = RNA_def_property(srna, "color1", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_funcs(prop, "rna_MeshColor_color1_get", "rna_MeshColor_color1_set", NULL);
RNA_def_property_ui_text(prop, "Color 1", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "color2", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_funcs(prop, "rna_MeshColor_color2_get", "rna_MeshColor_color2_set", NULL);
RNA_def_property_ui_text(prop, "Color 2", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "color3", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_funcs(prop, "rna_MeshColor_color3_get", "rna_MeshColor_color3_set", NULL);
RNA_def_property_ui_text(prop, "Color 3", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "color4", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_funcs(prop, "rna_MeshColor_color4_get", "rna_MeshColor_color4_set", NULL);
RNA_def_property_ui_text(prop, "Color 4", "");
@@ -2575,7 +2584,7 @@ static void rna_def_mloopcol(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_MeshColor_path");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_funcs(prop, "rna_MeshLoopColor_color_get", "rna_MeshLoopColor_color_set", NULL);
RNA_def_property_ui_text(prop, "Color", "");
@@ -2878,7 +2887,7 @@ static void rna_def_tessface_vertex_colors(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a vertex color layer to Mesh");
RNA_def_string(func, "name", "Col", 0, "", "Vertex color name");
parm = RNA_def_pointer(func, "layer", "MeshColorLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
@@ -2912,14 +2921,14 @@ static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a vertex color layer to Mesh");
RNA_def_string(func, "name", "Col", 0, "", "Vertex color name");
parm = RNA_def_pointer(func, "layer", "MeshLoopColorLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Mesh_vertex_color_remove");
RNA_def_function_ui_description(func, "Remove a vertex color layer");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "layer", "MeshLoopColorLayer", "", "The layer to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
@@ -2982,7 +2991,7 @@ static void rna_def_vertex_float_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a float property layer to Mesh");
RNA_def_string(func, "name", "Float Prop", 0, "", "Float property name");
parm = RNA_def_pointer(func, "layer", "MeshVertexFloatPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3003,7 +3012,7 @@ static void rna_def_vertex_int_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a integer property layer to Mesh");
RNA_def_string(func, "name", "Int Prop", 0, "", "Int property name");
parm = RNA_def_pointer(func, "layer", "MeshVertexIntPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3024,7 +3033,7 @@ static void rna_def_vertex_string_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a string property layer to Mesh");
RNA_def_string(func, "name", "String Prop", 0, "", "String property name");
parm = RNA_def_pointer(func, "layer", "MeshVertexStringPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3045,7 +3054,7 @@ static void rna_def_polygon_float_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a float property layer to Mesh");
RNA_def_string(func, "name", "Float Prop", 0, "", "Float property name");
parm = RNA_def_pointer(func, "layer", "MeshPolygonFloatPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3066,7 +3075,7 @@ static void rna_def_polygon_int_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a integer property layer to Mesh");
RNA_def_string(func, "name", "Int Prop", 0, "", "Int property name");
parm = RNA_def_pointer(func, "layer", "MeshPolygonIntPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3087,7 +3096,7 @@ static void rna_def_polygon_string_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a string property layer to Mesh");
RNA_def_string(func, "name", "String Prop", 0, "", "String property name");
parm = RNA_def_pointer(func, "layer", "MeshPolygonStringPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3111,7 +3120,7 @@ static void rna_def_tessface_uv_textures(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a UV tessface-texture layer to Mesh (only for meshes with no polygons)");
RNA_def_string(func, "name", "UVMap", 0, "", "UV map name");
parm = RNA_def_pointer(func, "layer", "MeshTextureFaceLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
@@ -3147,14 +3156,14 @@ static void rna_def_uv_textures(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a UV map layer to Mesh");
RNA_def_string(func, "name", "UVMap", 0, "", "UV map name");
parm = RNA_def_pointer(func, "layer", "MeshTexturePolyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Mesh_uv_texture_layers_remove");
RNA_def_function_ui_description(func, "Remove a vertex color layer");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "layer", "MeshTexturePolyLayer", "", "The layer to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshTexturePolyLayer");
@@ -3561,7 +3570,7 @@ static void rna_def_mesh(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_edge_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWCREASES);
- RNA_def_property_ui_text(prop, "Draw Creases", "Display creases created for subsurf weighting");
+ RNA_def_property_ui_text(prop, "Draw Creases", "Display creases created for Subdivision Surface modifier");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop = RNA_def_property(srna, "show_edge_bevel_weight", PROP_BOOLEAN, PROP_NONE);
@@ -3576,7 +3585,7 @@ static void rna_def_mesh(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_edge_sharp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWSHARP);
- RNA_def_property_ui_text(prop, "Draw Sharp", "Display sharp edges, used with the EdgeSplit modifier");
+ RNA_def_property_ui_text(prop, "Draw Sharp", "Display sharp edges, used with the Edge Split modifier");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop = RNA_def_property(srna, "show_freestyle_edge_marks", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index a3bc21b0170..9b0a25560f9 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -209,6 +209,11 @@ static void rna_Mesh_flip_normals(Mesh *mesh)
DAG_id_tag_update(&mesh->id, 0);
}
+static void rna_Mesh_split_faces(Mesh *mesh, int free_loop_normals)
+{
+ BKE_mesh_split_faces(mesh, free_loop_normals != 0);
+}
+
#else
void RNA_api_mesh(StructRNA *srna)
@@ -221,7 +226,7 @@ void RNA_api_mesh(StructRNA *srna)
RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix "
"(Warning: inverts normals if matrix is negative)");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
func = RNA_def_function(srna, "flip_normals", "rna_Mesh_flip_normals");
@@ -240,6 +245,11 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split");
RNA_def_function_ui_description(func, "Free split vertex normals");
+ func = RNA_def_function(srna, "split_faces", "rna_Mesh_split_faces");
+ RNA_def_function_ui_description(func, "Split faces based on the edge angle");
+ RNA_def_boolean(func, "free_loop_normals", 1, "Free Loop Notmals",
+ "Free loop normals custom data layer");
+
func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func,
@@ -264,9 +274,9 @@ void RNA_api_mesh(StructRNA *srna)
RNA_def_boolean(func, "use_bitflags", false, "", "Produce bitflags groups instead of simple numeric values");
/* return values */
parm = RNA_def_int_array(func, "poly_groups", 1, NULL, 0, 0, "", "Smooth Groups", 0, 0);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT);
parm = RNA_def_int(func, "groups", 0, 0, INT_MAX, "groups", "Total number of groups", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, 0, PARM_OUTPUT);
func = RNA_def_function(srna, "normals_split_custom_set", "rna_Mesh_normals_split_custom_set");
RNA_def_function_ui_description(func,
@@ -276,7 +286,7 @@ void RNA_api_mesh(StructRNA *srna)
/* TODO, see how array size of 0 works, this shouldnt be used */
parm = RNA_def_float_array(func, "normals", 1, NULL, -1.0f, 1.0f, "", "Normals", 0.0f, 0.0f);
RNA_def_property_multi_array(parm, 2, normals_array_dim);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
func = RNA_def_function(srna, "normals_split_custom_set_from_vertices",
"rna_Mesh_normals_split_custom_set_from_vertices");
@@ -287,7 +297,7 @@ void RNA_api_mesh(StructRNA *srna)
/* TODO, see how array size of 0 works, this shouldnt be used */
parm = RNA_def_float_array(func, "normals", 1, NULL, -1.0f, 1.0f, "", "Normals", 0.0f, 0.0f);
RNA_def_property_multi_array(parm, 2, normals_array_dim);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
func = RNA_def_function(srna, "update", "ED_mesh_update");
RNA_def_boolean(func, "calc_edges", 0, "Calculate Edges", "Force recalculation of edges");
@@ -317,4 +327,3 @@ void RNA_api_mesh(StructRNA *srna)
}
#endif
-
diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c
index 9d13bc90e72..91a65c7ccc5 100644
--- a/source/blender/makesrna/intern/rna_meta.c
+++ b/source/blender/makesrna/intern/rna_meta.c
@@ -280,8 +280,8 @@ static void rna_def_metaball_elements(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove an element from the metaball");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "element", "MetaElement", "", "The element 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "clear", "rna_MetaBall_elements_clear");
RNA_def_function_ui_description(func, "Remove all elements from the metaball");
diff --git a/source/blender/makesrna/intern/rna_meta_api.c b/source/blender/makesrna/intern/rna_meta_api.c
index 43dca6fe4f1..4c3fa787b94 100644
--- a/source/blender/makesrna/intern/rna_meta_api.c
+++ b/source/blender/makesrna/intern/rna_meta_api.c
@@ -45,7 +45,7 @@
#ifdef RNA_RUNTIME
static void rna_Meta_transform(struct MetaBall *mb, float *mat)
{
- BKE_mball_transform(mb, (float (*)[4])mat);
+ BKE_mball_transform(mb, (float (*)[4])mat, true);
DAG_id_tag_update(&mb->id, 0);
}
@@ -59,7 +59,7 @@ void RNA_api_meta(StructRNA *srna)
func = RNA_def_function(srna, "transform", "rna_Meta_transform");
RNA_def_function_ui_description(func, "Transform meta elements by a matrix");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index c4f0db38a16..a35d518b786 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -105,6 +105,7 @@ EnumPropertyItem rna_enum_object_modifier_type_items[] = {
{eModifierType_Shrinkwrap, "SHRINKWRAP", ICON_MOD_SHRINKWRAP, "Shrinkwrap", ""},
{eModifierType_SimpleDeform, "SIMPLE_DEFORM", ICON_MOD_SIMPLEDEFORM, "Simple Deform", ""},
{eModifierType_Smooth, "SMOOTH", ICON_MOD_SMOOTH, "Smooth", ""},
+ {eModifierType_SurfaceDeform, "SURFACE_DEFORM", ICON_MOD_MESHDEFORM, "Surface Deform", ""},
{eModifierType_Warp, "WARP", ICON_MOD_WARP, "Warp", ""},
{eModifierType_Wave, "WAVE", ICON_MOD_WAVE, "Wave", ""},
{0, "", 0, N_("Simulate"), ""},
@@ -408,6 +409,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_CorrectiveSmoothModifier;
case eModifierType_MeshSequenceCache:
return &RNA_MeshSequenceCacheModifier;
+ case eModifierType_SurfaceDeform:
+ return &RNA_SurfaceDeformModifier;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -573,6 +576,7 @@ RNA_MOD_OBJECT_SET(MeshDeform, object, OB_MESH);
RNA_MOD_OBJECT_SET(NormalEdit, target, OB_EMPTY);
RNA_MOD_OBJECT_SET(Shrinkwrap, target, OB_MESH);
RNA_MOD_OBJECT_SET(Shrinkwrap, auxTarget, OB_MESH);
+RNA_MOD_OBJECT_SET(SurfaceDeform, target, OB_MESH);
static void rna_HookModifier_object_set(PointerRNA *ptr, PointerRNA value)
{
@@ -1131,6 +1135,11 @@ static int rna_CorrectiveSmoothModifier_is_bind_get(PointerRNA *ptr)
return (csmd->bind_coords != NULL);
}
+static int rna_SurfaceDeformModifier_is_bound_get(PointerRNA *ptr)
+{
+ return (((SurfaceDeformModifierData *)ptr->data)->verts != NULL);
+}
+
static void rna_MeshSequenceCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
#ifdef WITH_ALEMBIC
@@ -1509,12 +1518,40 @@ static void rna_def_modifier_mirror(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mirror_u", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_MIRROR_U);
- RNA_def_property_ui_text(prop, "Mirror U", "Mirror the U texture coordinate around the 0.5 point");
+ RNA_def_property_ui_text(prop, "Mirror U", "Mirror the U texture coordinate around the flip offset point");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_mirror_v", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_MIRROR_V);
- RNA_def_property_ui_text(prop, "Mirror V", "Mirror the V texture coordinate around the 0.5 point");
+ RNA_def_property_ui_text(prop, "Mirror V", "Mirror the V texture coordinate around the flip offset point");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "mirror_offset_u", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset[0]");
+ RNA_def_property_range(prop, -1, 1);
+ RNA_def_property_ui_range(prop, -1, 1, 2, 4);
+ RNA_def_property_ui_text(prop, "Flip U Offset", "Amount to offset mirrored UVs flipping point from the 0.5 on the U axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "mirror_offset_v", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset[1]");
+ RNA_def_property_range(prop, -1, 1);
+ RNA_def_property_ui_range(prop, -1, 1, 2, 4);
+ RNA_def_property_ui_text(prop, "Flip V Offset", "Amount to offset mirrored UVs flipping point from the 0.5 point on the V axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "offset_u", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset_copy[0]");
+ RNA_def_property_range(prop, -10000.0f, 10000.0f);
+ RNA_def_property_ui_range(prop, -1, 1, 2, 4);
+ RNA_def_property_ui_text(prop, "U Offset", "Mirrored UV offset on the U axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "offset_v", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset_copy[1]");
+ RNA_def_property_range(prop, -10000.0f, 10000.0f);
+ RNA_def_property_ui_range(prop, -1, 1, 2, 4);
+ RNA_def_property_ui_text(prop, "V Offset", "Mirrored UV offset on the V axis");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE);
@@ -1951,9 +1988,26 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
prop = RNA_def_property(srna, "double_threshold", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "double_threshold");
RNA_def_property_range(prop, 0, 1.0f);
- RNA_def_property_ui_range(prop, 0, 1, 0.0001, 7);
+ RNA_def_property_ui_range(prop, 0, 1, 0.0001, 6);
RNA_def_property_ui_text(prop, "Overlap Threshold", "Threshold for checking overlapping geometry");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ /* BMesh debugging options, only used when G_DEBUG is set */
+
+ /* BMesh intersection options */
+ static EnumPropertyItem debug_items[] = {
+ {eBooleanModifierBMeshFlag_BMesh_Separate, "SEPARATE", 0, "Separate", ""},
+ {eBooleanModifierBMeshFlag_BMesh_NoDissolve, "NO_DISSOLVE", 0, "No Dissolve", ""},
+ {eBooleanModifierBMeshFlag_BMesh_NoConnectRegions, "NO_CONNECT_REGIONS", 0, "No Connect Regions", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ prop = RNA_def_property(srna, "debug_options", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, debug_items);
+ RNA_def_property_enum_sdna(prop, NULL, "bm_flag");
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_ui_text(prop, "Debug", "Debugging options, only when started with '-d'");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_array(BlenderRNA *brna)
@@ -3390,6 +3444,13 @@ static void rna_def_modifier_screw(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Screw", "Offset the revolution along its axis");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "merge_dist");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1, 1, 4);
+ RNA_def_property_ui_text(prop, "Merge Distance", "Limit below which to merge vertices");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "use_normal_flip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_NORMAL_FLIP);
RNA_def_property_ui_text(prop, "Flip", "Flip normals of lathed faces");
@@ -3405,6 +3466,12 @@ static void rna_def_modifier_screw(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Object Screw", "Use the distance between the objects to make a screw");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ /* Vertex merging parameters */
+ prop = RNA_def_property(srna, "use_merge_vertices", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_MERGE);
+ RNA_def_property_ui_text(prop, "Merge Vertices", "Merge adjacent vertices (screw offset must be zero)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "use_smooth_shade", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_SMOOTH_SHADING);
RNA_def_property_ui_text(prop, "Smooth Shading", "Output faces with smooth shading rather than flat shaded");
@@ -4702,6 +4769,33 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+static void rna_def_modifier_surfacedeform(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SurfaceDeformModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "SurfaceDeform Modifier", "");
+ RNA_def_struct_sdna(srna, "SurfaceDeformModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM);
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Target", "Mesh object to deform with");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_SurfaceDeformModifier_target_set", NULL, "rna_Mesh_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 2.0f, 16.0f);
+ RNA_def_property_ui_text(prop, "Interpolation falloff", "Controls how much nearby polygons influence deformation");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "is_bound", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_SurfaceDeformModifier_is_bound_get", NULL);
+ RNA_def_property_ui_text(prop, "Bound", "Whether geometry has been bound to target mesh");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+}
+
void RNA_def_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4819,6 +4913,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_datatransfer(brna);
rna_def_modifier_normaledit(brna);
rna_def_modifier_meshseqcache(brna);
+ rna_def_modifier_surfacedeform(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index 55bc40f573c..d72c858a5d5 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -508,7 +508,7 @@ static void rna_def_strip_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
"of all F-Curves in the NLA strip.");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX);
parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "The found F-Curve, or None if it doesn't exist");
@@ -659,11 +659,17 @@ static void rna_def_nlastrip(BlenderRNA *brna)
prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Influence", "Amount the strip contributes to the current result");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
+ /* XXX: Update temporarily disabled so that the property can be edited at all!
+ * Even autokey only applies after the curves have been re-evaluated, causing the unkeyed values to be lost
+ */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, /*"rna_NlaStrip_update"*/ NULL);
prop = RNA_def_property(srna, "strip_time", PROP_FLOAT, PROP_TIME);
RNA_def_property_ui_text(prop, "Strip Time", "Frame of referenced Action to evaluate");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
+ /* XXX: Update temporarily disabled so that the property can be edited at all!
+ * Even autokey only applies after the curves have been re-evaluated, causing the unkeyed values to be lost
+ */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, /*"rna_NlaStrip_update"*/ NULL);
/* TODO: should the animated_influence/time settings be animatable themselves? */
prop = RNA_def_property(srna, "use_animated_influence", PROP_BOOLEAN, PROP_NONE);
@@ -733,12 +739,12 @@ static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new Action-Clip strip to the track");
parm = RNA_def_string(func, "name", "NlaStrip", 0, "", "Name for the NLA Strips");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "start", 0, INT_MIN, INT_MAX, "Start Frame",
"Start frame for this strip", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "action", "Action", "", "Action to assign to this strip");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "strip", "NlaStrip", "", "New NLA Strip");
RNA_def_function_return(func, parm);
@@ -747,8 +753,8 @@ static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a NLA Strip");
parm = RNA_def_pointer(func, "strip", "NlaStrip", "", "NLA Strip 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_nlatrack(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 47e9d989dbf..523c5c219d8 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -64,6 +64,8 @@
#include "RE_render_ext.h"
+#include "NOD_composite.h"
+
EnumPropertyItem rna_enum_node_socket_in_out_items[] = {
{ SOCK_IN, "IN", 0, "Input", "" },
{ SOCK_OUT, "OUT", 0, "Output", "" },
@@ -71,6 +73,13 @@ EnumPropertyItem rna_enum_node_socket_in_out_items[] = {
};
#ifndef RNA_RUNTIME
+static EnumPropertyItem rna_enum_node_socket_draw_shape_items[] = {
+ {SOCK_DRAW_SHAPE_CIRCLE, "CIRCLE", 0, "Circle", ""},
+ {SOCK_DRAW_SHAPE_SQUARE, "SQUARE", 0, "Square", ""},
+ {SOCK_DRAW_SHAPE_DIAMOND, "DIAMOND", 0, "Diamond", ""},
+ {0, NULL, 0, NULL, NULL }
+};
+
static EnumPropertyItem node_socket_type_items[] = {
{SOCK_CUSTOM, "CUSTOM", 0, "Custom", ""},
{SOCK_FLOAT, "VALUE", 0, "Value", ""},
@@ -236,10 +245,10 @@ bNodeTreeType *rna_node_tree_type_from_enum(int value)
EnumPropertyItem *rna_node_tree_type_itemf(void *data, int (*poll)(void *data, bNodeTreeType *), bool *r_free)
{
- EnumPropertyItem tmp = {0, "", 0, "", ""};
+ EnumPropertyItem tmp = {0};
EnumPropertyItem *item = NULL;
int totitem = 0, i = 0;
-
+
NODE_TREE_TYPES_BEGIN (nt)
{
if (poll && !poll(data, nt)) {
@@ -259,9 +268,14 @@ EnumPropertyItem *rna_node_tree_type_itemf(void *data, int (*poll)(void *data, b
}
NODE_TREE_TYPES_END;
+ if (totitem == 0) {
+ *r_free = false;
+ return DummyRNA_NULL_items;
+ }
+
RNA_enum_item_end(&item, &totitem);
*r_free = true;
-
+
return item;
}
@@ -308,9 +322,9 @@ bNodeType *rna_node_type_from_enum(int value)
EnumPropertyItem *rna_node_type_itemf(void *data, int (*poll)(void *data, bNodeType *), bool *r_free)
{
EnumPropertyItem *item = NULL;
- EnumPropertyItem tmp = {0, "", 0, "", ""};
+ EnumPropertyItem tmp = {0};
int totitem = 0, i = 0;
-
+
NODE_TYPES_BEGIN(ntype)
if (poll && !poll(data, ntype)) {
++i;
@@ -327,9 +341,15 @@ EnumPropertyItem *rna_node_type_itemf(void *data, int (*poll)(void *data, bNodeT
++i;
NODE_TYPES_END
+
+ if (totitem == 0) {
+ *r_free = false;
+ return DummyRNA_NULL_items;
+ }
+
RNA_enum_item_end(&item, &totitem);
*r_free = true;
-
+
return item;
}
@@ -376,10 +396,10 @@ bNodeSocketType *rna_node_socket_type_from_enum(int value)
EnumPropertyItem *rna_node_socket_type_itemf(void *data, int (*poll)(void *data, bNodeSocketType *), bool *r_free)
{
EnumPropertyItem *item = NULL;
- EnumPropertyItem tmp = {0, "", 0, "", ""};
+ EnumPropertyItem tmp = {0};
int totitem = 0, i = 0;
StructRNA *srna;
-
+
NODE_SOCKET_TYPES_BEGIN(stype)
if (poll && !poll(data, stype)) {
++i;
@@ -397,9 +417,15 @@ EnumPropertyItem *rna_node_socket_type_itemf(void *data, int (*poll)(void *data,
++i;
NODE_SOCKET_TYPES_END
+
+ if (totitem == 0) {
+ *r_free = false;
+ return DummyRNA_NULL_items;
+ }
+
RNA_enum_item_end(&item, &totitem);
*r_free = true;
-
+
return item;
}
@@ -408,25 +434,25 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer
EnumPropertyItem *item = NULL;
EnumPropertyItem tmp;
int totitem = 0;
-
+
/* hack, don't want to add include path to RNA just for this, since in the future RNA types
* for nodes should be defined locally at runtime anyway ...
*/
-
+
tmp.value = NODE_CUSTOM;
tmp.identifier = "CUSTOM";
tmp.name = "Custom";
tmp.description = "Custom Node";
tmp.icon = ICON_NONE;
RNA_enum_item_add(&item, &totitem, &tmp);
-
+
tmp.value = NODE_UNDEFINED;
tmp.identifier = "UNDEFINED";
tmp.name = "UNDEFINED";
tmp.description = "";
tmp.icon = ICON_NONE;
RNA_enum_item_add(&item, &totitem, &tmp);
-
+
#define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
if (STREQ(#Category, "Node")) { \
tmp.value = ID; \
@@ -438,7 +464,7 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer
}
#include "../../nodes/NOD_static_types.h"
#undef DefNode
-
+
if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) {
#define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
if (STREQ(#Category, "ShaderNode")) { \
@@ -466,7 +492,7 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer
#include "../../nodes/NOD_static_types.h"
#undef DefNode
}
-
+
if (RNA_struct_is_a(ptr->type, &RNA_TextureNode)) {
#define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
if (STREQ(#Category, "TextureNode")) { \
@@ -483,7 +509,7 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer
RNA_enum_item_end(&item, &totitem);
*r_free = true;
-
+
return item;
}
@@ -576,11 +602,10 @@ static void rna_NodeTree_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
RNA_struct_free_extension(type, &nt->ext);
+ RNA_struct_free(&BLENDER_RNA, type);
ntreeTypeFreeLink(nt);
- RNA_struct_free(&BLENDER_RNA, type);
-
/* update while blender is running */
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
}
@@ -612,9 +637,10 @@ static StructRNA *rna_NodeTree_register(
/* check if we have registered this tree type before, and remove it */
nt = ntreeTypeFind(dummynt.idname);
- if (nt)
+ if (nt) {
rna_NodeTree_unregister(bmain, nt->ext.srna);
-
+ }
+
/* create a new node tree type */
nt = MEM_callocN(sizeof(bNodeTreeType), "node tree type");
memcpy(nt, &dummynt, sizeof(dummynt));
@@ -1329,11 +1355,11 @@ static void rna_Node_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
RNA_struct_free_extension(type, &nt->ext);
+ RNA_struct_free(&BLENDER_RNA, type);
/* this also frees the allocated nt pointer, no MEM_free call needed! */
nodeUnregisterType(nt);
- RNA_struct_free(&BLENDER_RNA, type);
/* update while blender is running */
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
@@ -1374,8 +1400,9 @@ static bNodeType *rna_Node_register_base(Main *bmain, ReportList *reports, Struc
/* check if we have registered this node type before, and remove it */
nt = nodeTypeFind(dummynt.idname);
- if (nt)
+ if (nt) {
rna_Node_unregister(bmain, nt->ext.srna);
+ }
/* create a new node type */
nt = MEM_callocN(sizeof(bNodeType), "node type");
@@ -1791,10 +1818,10 @@ static void rna_NodeSocket_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
RNA_struct_free_extension(type, &st->ext_socket);
+ RNA_struct_free(&BLENDER_RNA, type);
nodeUnregisterSocketType(st);
- RNA_struct_free(&BLENDER_RNA, type);
/* update while blender is running */
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
@@ -2608,16 +2635,16 @@ static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *p
rna_Node_update(bmain, scene, ptr);
if (scene->nodetree != NULL) {
- ntreeCompositForceHidden(scene->nodetree);
+ ntreeCompositUpdateRLayers(scene->nodetree);
}
}
static EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl)
{
EnumPropertyItem *item = NULL;
- EnumPropertyItem tmp = {0, "", 0, "", ""};
+ EnumPropertyItem tmp = {0};
int i = 0, totitem = 0;
-
+
while (rl) {
tmp.identifier = rl->name;
/* little trick: using space char instead empty string makes the item selectable in the dropdown */
@@ -2629,7 +2656,7 @@ static EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl)
RNA_enum_item_add(&item, &totitem, &tmp);
rl = rl->next;
}
-
+
RNA_enum_item_end(&item, &totitem);
return item;
@@ -2642,18 +2669,17 @@ static EnumPropertyItem *rna_Node_image_layer_itemf(bContext *UNUSED(C), Pointer
Image *ima = (Image *)node->id;
EnumPropertyItem *item = NULL;
RenderLayer *rl;
-
- if (ima && ima->rr) {
- rl = ima->rr->layers.first;
- item = renderresult_layers_add_enum(rl);
- }
- else {
- int totitem = 0;
- RNA_enum_item_end(&item, &totitem);
+
+ if (ima == NULL || ima->rr == NULL) {
+ *r_free = false;
+ return DummyRNA_NULL_items;
}
-
+
+ rl = ima->rr->layers.first;
+ item = renderresult_layers_add_enum(rl);
+
*r_free = true;
-
+
return item;
}
@@ -2704,19 +2730,22 @@ static EnumPropertyItem *renderresult_views_add_enum(RenderView *rv)
}
static EnumPropertyItem *rna_Node_image_view_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *free)
+ PropertyRNA *UNUSED(prop), bool *r_free)
{
bNode *node = (bNode *)ptr->data;
Image *ima = (Image *)node->id;
EnumPropertyItem *item = NULL;
RenderView *rv;
- if (!ima || !(ima->rr)) return NULL;
+ if (ima == NULL || ima->rr == NULL) {
+ *r_free = false;
+ return DummyRNA_NULL_items;
+ }
rv = ima->rr->views.first;
item = renderresult_views_add_enum(rv);
- *free = true;
+ *r_free = true;
return item;
}
@@ -2728,18 +2757,17 @@ static EnumPropertyItem *rna_Node_scene_layer_itemf(bContext *UNUSED(C), Pointer
Scene *sce = (Scene *)node->id;
EnumPropertyItem *item = NULL;
RenderLayer *rl;
-
- if (sce) {
- rl = sce->r.layers.first;
- item = renderresult_layers_add_enum(rl);
- }
- else {
- int totitem = 0;
- RNA_enum_item_end(&item, &totitem);
+
+ if (sce == NULL) {
+ *r_free = false;
+ return DummyRNA_NULL_items;
}
-
+
+ rl = sce->r.layers.first;
+ item = renderresult_layers_add_enum(rl);
+
*r_free = true;
-
+
return item;
}
@@ -2747,7 +2775,7 @@ static void rna_Node_scene_layer_update(Main *bmain, Scene *scene, PointerRNA *p
{
rna_Node_update(bmain, scene, ptr);
if (scene->nodetree != NULL) {
- ntreeCompositForceHidden(scene->nodetree);
+ ntreeCompositUpdateRLayers(scene->nodetree);
}
}
@@ -2756,7 +2784,7 @@ static EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C), PointerRNA
{
bNode *node = (bNode *)ptr->data;
EnumPropertyItem *item = NULL;
- EnumPropertyItem tmp = {0, "", 0, "", ""};
+ EnumPropertyItem tmp = {0};
int totitem = 0;
switch (node->custom1) {
@@ -2793,7 +2821,7 @@ static EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C), PointerRNA
RNA_enum_item_add(&item, &totitem, &tmp);
break;
default:
- break;
+ return DummyRNA_NULL_items;
}
RNA_enum_item_end(&item, &totitem);
@@ -2995,6 +3023,15 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p
ED_node_tag_update_nodetree(bmain, ntree, node);
}
+static void rna_ShaderNodePrincipled_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bNodeTree *ntree = (bNodeTree *)ptr->id.data;
+ bNode *node = (bNode *)ptr->data;
+
+ nodeUpdate(ntree, node);
+ rna_Node_update(bmain, scene, ptr);
+}
+
static void rna_ShaderNodeSubsurface_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
@@ -3107,6 +3144,9 @@ void rna_ShaderNodePointDensity_density_cache(bNode *self,
sizeof(pd->vertex_attribute_name));
}
+ /* Store resolution, so it can be changed in the UI. */
+ shader_point_density->cached_resolution = shader_point_density->resolution;
+
/* Single-threaded sampling of the voxel domain. */
RE_point_density_cache(scene,
pd,
@@ -3121,15 +3161,15 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
{
NodeShaderTexPointDensity *shader_point_density = self->storage;
PointDensity *pd = &shader_point_density->pd;
+ const int resolution = shader_point_density->cached_resolution;
if (scene == NULL) {
*length = 0;
return;
}
- *length = 4 * shader_point_density->resolution *
- shader_point_density->resolution *
- shader_point_density->resolution;
+ /* TODO(sergey): Will likely overflow, but how to pass size_t via RNA? */
+ *length = 4 * resolution * resolution * resolution;
if (*values == NULL) {
*values = MEM_mallocN(sizeof(float) * (*length), "point density dynamic array");
@@ -3137,13 +3177,14 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
/* Single-threaded sampling of the voxel domain. */
RE_point_density_sample(scene, pd,
- shader_point_density->resolution,
+ resolution,
settings == 1,
*values);
/* We're done, time to clean up. */
BKE_texture_pointdensity_free_data(pd);
memset(pd, 0, sizeof(*pd));
+ shader_point_density->cached_resolution = 0.0f;
}
void rna_ShaderNodePointDensity_density_minmax(bNode *self,
@@ -3250,6 +3291,12 @@ static EnumPropertyItem node_script_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static EnumPropertyItem node_principled_distribution_items[] = {
+ { SHD_GLOSSY_GGX, "GGX", 0, "GGX", "" },
+ { SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", "" },
+ { 0, NULL, 0, NULL, NULL }
+};
+
/* -- Common nodes ---------------------------------------------------------- */
static void def_group_input(StructRNA *srna)
@@ -3318,11 +3365,12 @@ static void def_frame(StructRNA *srna)
prop = RNA_def_property(srna, "text", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_struct_type(prop, "Text");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Text", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_struct_sdna_from(srna, "NodeFrame", "storage");
+ RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_ID_NODETREE);
prop = RNA_def_property(srna, "shrink", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_FRAME_SHRINK);
@@ -3587,7 +3635,7 @@ static void def_sh_lamp(StructRNA *srna)
prop = RNA_def_property(srna, "lamp_object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Lamp_object_poll");
RNA_def_property_ui_text(prop, "Lamp Object", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -3673,7 +3721,7 @@ static const EnumPropertyItem sh_tex_prop_interpolation_items[] = {
{SHD_INTERP_CLOSEST, "Closest", 0, "Closest",
"No interpolation (sample closest texel)"},
{SHD_INTERP_CUBIC, "Cubic", 0, "Cubic",
- "Cubic interpolation (CPU only)"},
+ "Cubic interpolation"},
{SHD_INTERP_SMART, "Smart", 0, "Smart",
"Bicubic when magnifying, else bilinear (OSL only)"},
{0, NULL, 0, NULL, NULL}
@@ -3961,7 +4009,7 @@ static void def_sh_tex_coord(StructRNA *srna)
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Object", "Use coordinates from this object (for object texture coordinates output)");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -4021,7 +4069,9 @@ static void def_sh_tex_wireframe(StructRNA *srna)
static void def_sh_tex_pointdensity(StructRNA *srna)
{
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
static EnumPropertyItem point_source_items[] = {
{SHD_POINTDENSITY_SOURCE_PSYS, "PARTICLE_SYSTEM", 0, "Particle System",
@@ -4037,7 +4087,7 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
{SHD_INTERP_LINEAR, "Linear", 0, "Linear",
"Linear interpolation"},
{SHD_INTERP_CUBIC, "Cubic", 0, "Cubic",
- "Cubic interpolation (CPU only)"},
+ "Cubic interpolation"},
{0, NULL, 0, NULL, NULL}
};
@@ -4075,7 +4125,7 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Object", "Object to take point data from");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -4141,22 +4191,22 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
RNA_def_pointer(func, "scene", "Scene", "", "");
RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
/* TODO, See how array size of 0 works, this shouldnt be used. */
- prop = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_function_output(func, prop);
+ parm = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, 0);
+ RNA_def_function_output(func, parm);
func = RNA_def_function(srna, "calc_point_density_minmax", "rna_ShaderNodePointDensity_density_minmax");
RNA_def_function_ui_description(func, "Calculate point density");
RNA_def_pointer(func, "scene", "Scene", "", "");
RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
- prop = RNA_def_property(func, "min", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_array(prop, 3);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
- prop = RNA_def_property(func, "max", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_array(prop, 3);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_array(parm, 3);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_property(func, "max", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_array(parm, 3);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
}
static void def_glossy(StructRNA *srna)
@@ -4181,6 +4231,17 @@ static void def_glass(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_principled(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_principled_distribution_items);
+ RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodePrincipled_update");
+}
+
static void def_refraction(StructRNA *srna)
{
PropertyRNA *prop;
@@ -4392,7 +4453,7 @@ static void def_sh_script(StructRNA *srna)
func = RNA_def_function(srna, "find_socket", "rna_ShaderNodeScript_find_socket");
RNA_def_function_ui_description(func, "Find a socket by name");
parm = RNA_def_string(func, "name", NULL, 0, "Socket name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/*parm =*/ RNA_def_boolean(func, "is_output", false, "Output", "Whether the socket is an output");
parm = RNA_def_pointer(func, "result", "NodeSocket", "", "");
RNA_def_function_return(func, parm);
@@ -4401,9 +4462,9 @@ static void def_sh_script(StructRNA *srna)
RNA_def_function_ui_description(func, "Add a socket socket");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", node_socket_type_items, SOCK_FLOAT, "Type", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/*parm =*/ RNA_def_boolean(func, "is_output", false, "Output", "Whether the socket is an output");
parm = RNA_def_pointer(func, "result", "NodeSocket", "", "");
RNA_def_function_return(func, parm);
@@ -4412,7 +4473,7 @@ static void def_sh_script(StructRNA *srna)
RNA_def_function_ui_description(func, "Remove a socket socket");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "sock", "NodeSocket", "Socket", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
#endif
}
@@ -4437,31 +4498,6 @@ static void def_cmp_alpha_over(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_cmp_hue_saturation(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeHueSat", "storage");
-
- prop = RNA_def_property(srna, "color_hue", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "hue");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Hue", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "color_saturation", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sat");
- RNA_def_property_range(prop, 0.0f, 2.0f);
- RNA_def_property_ui_text(prop, "Saturation", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "color_value", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "val");
- RNA_def_property_range(prop, 0.0f, 2.0f);
- RNA_def_property_ui_text(prop, "Value", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
static void def_cmp_blur(StructRNA *srna)
{
PropertyRNA *prop;
@@ -4786,9 +4822,9 @@ static void def_cmp_render_layers(StructRNA *srna)
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_pointer_funcs(prop, NULL, "rna_Node_scene_set", NULL, NULL);
RNA_def_property_struct_type(prop, "Scene");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Scene", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_scene_layer_update");
prop = RNA_def_property(srna, "layer", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
@@ -4854,7 +4890,7 @@ static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Add a file slot to this node");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return value */
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket");
RNA_def_function_return(func, parm);
@@ -4867,7 +4903,7 @@ static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Remove a file slot from this node");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "The socket to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "clear", "rna_Node_inputs_clear");
RNA_def_function_ui_description(func, "Remove all file slots from this node");
@@ -4877,9 +4913,9 @@ static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Move a file slot to another position");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void def_cmp_output_file(BlenderRNA *brna, StructRNA *srna)
{
@@ -5229,6 +5265,16 @@ static void def_cmp_luma_matte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_cmp_brightcontrast(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "use_premultiply", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
+ RNA_def_property_ui_text(prop, "Convert Premul", "Keep output image premultiplied alpha");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_cmp_chroma_matte(StructRNA *srna)
{
PropertyRNA *prop;
@@ -5433,7 +5479,7 @@ static void def_cmp_defocus(StructRNA *srna)
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_pointer_funcs(prop, NULL, "rna_Node_scene_set", NULL, NULL);
RNA_def_property_struct_type(prop, "Scene");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Scene", "Scene from which to select the active camera (render scene if undefined)");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -5740,8 +5786,8 @@ static void def_cmp_glare(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "streaks", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "angle");
- RNA_def_property_range(prop, 2, 16);
+ RNA_def_property_int_sdna(prop, NULL, "streaks");
+ RNA_def_property_range(prop, 1, 16);
RNA_def_property_ui_text(prop, "Streaks", "Total number of streaks");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -5758,7 +5804,7 @@ static void def_cmp_glare(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "use_rotate_45", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "angle", 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "star_45", 0);
RNA_def_property_ui_text(prop, "Rotate 45", "Simple star filter: add 45 degree rotation offset");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -6300,14 +6346,8 @@ static void def_cmp_switch(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_cmp_switch_view(StructRNA *srna)
+static void def_cmp_switch_view(StructRNA *UNUSED(srna))
{
- PropertyRNA *prop;
-
- prop = RNA_def_property(srna, "check", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "custom1", 0);
- RNA_def_property_ui_text(prop, "Switch", "Off: first socket, On: second socket");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_cmp_colorcorrection(StructRNA *srna)
@@ -6954,6 +6994,13 @@ static void rna_def_node_socket(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Type", "Data type");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocket_update");
+ prop = RNA_def_property(srna, "draw_shape", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "draw_shape");
+ RNA_def_property_enum_items(prop, rna_enum_node_socket_draw_shape_items);
+ RNA_def_property_enum_default(prop, SOCK_DRAW_SHAPE_CIRCLE);
+ RNA_def_property_ui_text(prop, "Shape", "Socket shape");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocket_update");
+
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname");
@@ -6965,29 +7012,29 @@ static void rna_def_node_socket(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Draw socket");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "Node");
RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_property(func, "text", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(parm, "Text", "Text label to draw alongside properties");
// RNA_def_property_string_default(parm, "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "draw_color", NULL);
RNA_def_function_ui_description(func, "Color of the socket icon");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "Node");
RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
RNA_def_function_output(func, parm);
}
@@ -7038,17 +7085,17 @@ static void rna_def_node_socket_interface(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Draw template settings");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
func = RNA_def_function(srna, "draw_color", NULL);
RNA_def_function_ui_description(func, "Color of the socket icon");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
RNA_def_function_output(func, parm);
@@ -7056,25 +7103,25 @@ static void rna_def_node_socket_interface(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Define RNA properties of a socket");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "data_rna_type", "Struct", "Data RNA Type", "RNA type for special socket properties");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "init_socket", NULL);
RNA_def_function_ui_description(func, "Initialize a node socket instance");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "node", "Node", "Node", "Node of the socket to initialize");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "Socket", "Socket to initialize");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "Path to specialized socket data");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "from_socket", NULL);
RNA_def_function_ui_description(func, "Setup template parameters from an existing socket");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "node", "Node", "Node", "Node of the original socket");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "Socket", "Original socket");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
}
static void rna_def_node_socket_float(BlenderRNA *brna, const char *idname, const char *interface_idname, PropertySubType subtype)
@@ -7409,29 +7456,29 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Draw socket");
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "Node");
RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_property(func, "text", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(parm, "Text", "Text label to draw alongside properties");
// RNA_def_property_string_default(parm, "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "draw_color", "rna_NodeSocketStandard_draw_color");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Color of the socket icon");
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "Node");
RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
RNA_def_function_output(func, parm);
@@ -7451,17 +7498,17 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Draw template settings");
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
func = RNA_def_function(srna, "draw_color", "rna_NodeSocketInterfaceStandard_draw_color");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Color of the socket icon");
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
RNA_def_function_output(func, parm);
@@ -7543,13 +7590,13 @@ static void rna_def_internal_node(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", ""));
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "poll_instance", "rna_NodeInternal_poll_instance");
RNA_def_function_ui_description(func, "If non-null output is returned, the node can be added to the tree");
RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", ""));
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* update */
func = RNA_def_function(srna, "update", "rna_NodeInternal_update");
@@ -7561,22 +7608,22 @@ static void rna_def_internal_node(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Draw node buttons");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* draw buttons extended */
func = RNA_def_function(srna, "draw_buttons_ext", "rna_NodeInternal_draw_buttons_ext");
RNA_def_function_ui_description(func, "Draw node buttons in the sidebar");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
}
static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int in_out)
@@ -7599,9 +7646,9 @@ static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int i
RNA_def_function_ui_description(func, "Add a socket to this node");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_string(func, "identifier", NULL, MAX_NAME, "Identifier", "Unique socket identifier");
/* return value */
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket");
@@ -7611,7 +7658,7 @@ static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int i
RNA_def_function_ui_description(func, "Remove a socket from this node");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "The socket to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "clear", clearfunc);
RNA_def_function_ui_description(func, "Remove all sockets from this node");
@@ -7621,9 +7668,9 @@ static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int i
RNA_def_function_ui_description(func, "Move a socket to another position");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_node(BlenderRNA *brna)
@@ -7774,7 +7821,7 @@ static void rna_def_node(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Update after property changes");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
func = RNA_def_function(srna, "is_registered_node_type", "rna_Node_is_registered_node_type");
RNA_def_function_ui_description(func, "True if a registered node type");
@@ -7849,14 +7896,14 @@ static void rna_def_node(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", ""));
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "poll_instance", NULL);
RNA_def_function_ui_description(func, "If non-null output is returned, the node can be added to the tree");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", ""));
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* update */
func = RNA_def_function(srna, "update", NULL);
@@ -7868,21 +7915,21 @@ static void rna_def_node(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Handle creation of a link to or from the node");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "link", "NodeLink", "Link", "Node link that will be inserted");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* init */
func = RNA_def_function(srna, "init", NULL);
RNA_def_function_ui_description(func, "Initialize a new instance of this node");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* copy */
func = RNA_def_function(srna, "copy", NULL);
RNA_def_function_ui_description(func, "Initialize a new instance of this node from an existing node");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "node", "Node", "Node", "Existing node to copy");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* free */
func = RNA_def_function(srna, "free", NULL);
@@ -7894,29 +7941,29 @@ static void rna_def_node(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Draw node buttons");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* draw buttons extended */
func = RNA_def_function(srna, "draw_buttons_ext", NULL);
RNA_def_function_ui_description(func, "Draw node buttons in the sidebar");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* dynamic label */
func = RNA_def_function(srna, "draw_label", NULL);
RNA_def_function_ui_description(func, "Returns a dynamic label string");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_string(func, "label", NULL, MAX_NAME, "Label", "");
- RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
}
@@ -7983,7 +8030,7 @@ static void rna_def_nodetree_nodes_api(BlenderRNA *brna, PropertyRNA *cprop)
* added this here to avoid frequent confusion with API changes from "type" to "bl_idname"
*/
parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Type of node to add (Warning: should be same as node.bl_idname, not node.type!)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return value */
parm = RNA_def_pointer(func, "node", "Node", "", "New node");
RNA_def_function_return(func, parm);
@@ -7992,8 +8039,8 @@ static void rna_def_nodetree_nodes_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a node from this node tree");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "node", "Node", "", "The node 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "clear", "rna_NodeTree_node_clear");
RNA_def_function_ui_description(func, "Remove all nodes from this node tree");
@@ -8022,9 +8069,9 @@ static void rna_def_nodetree_link_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a node link to this node tree");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "input", "NodeSocket", "", "The input socket");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "output", "NodeSocket", "", "The output socket");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
RNA_def_boolean(func, "verify_limits", true, "Verify Limits", "Remove existing links if connection limit is exceeded");
/* return */
parm = RNA_def_pointer(func, "link", "NodeLink", "", "New node link");
@@ -8034,8 +8081,8 @@ static void rna_def_nodetree_link_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "remove a node link from the node tree");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "link", "NodeLink", "", "The node link 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "clear", "rna_NodeTree_link_clear");
RNA_def_function_ui_description(func, "remove all node links from the node tree");
@@ -8062,9 +8109,9 @@ static void rna_def_node_tree_sockets_api(BlenderRNA *brna, PropertyRNA *cprop,
RNA_def_function_ui_description(func, "Add a socket to this node tree");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return value */
parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "New socket");
RNA_def_function_return(func, parm);
@@ -8073,7 +8120,7 @@ static void rna_def_node_tree_sockets_api(BlenderRNA *brna, PropertyRNA *cprop,
RNA_def_function_ui_description(func, "Remove a socket from this node tree");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "The socket to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "clear", clearfunc);
RNA_def_function_ui_description(func, "Remove all sockets from this node tree");
@@ -8082,9 +8129,9 @@ static void rna_def_node_tree_sockets_api(BlenderRNA *brna, PropertyRNA *cprop,
func = RNA_def_function(srna, "move", movefunc);
RNA_def_function_ui_description(func, "Move a socket to another position");
parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_nodetree(BlenderRNA *brna)
@@ -8172,7 +8219,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
func = RNA_def_function(srna, "interface_update", "rna_NodeTree_interface_update");
RNA_def_function_ui_description(func, "Updated node group interface");
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
@@ -8201,7 +8248,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Check visibility in the editor");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", ""));
/* update */
@@ -8214,7 +8261,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Get a node tree from the context");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "result_1", "NodeTree", "Node Tree", "Active node tree from context");
RNA_def_function_output(func, parm);
parm = RNA_def_pointer(func, "result_2", "ID", "Owner ID", "ID data-block that owns the node tree");
@@ -8318,10 +8365,10 @@ static StructRNA *define_specific_node(BlenderRNA *brna, const char *struct_name
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE);
parm = RNA_def_property(func, "index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Index", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "result", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "NodeInternalSocketTemplate");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "output_template", "rna_NodeInternal_output_template");
@@ -8329,10 +8376,10 @@ static StructRNA *define_specific_node(BlenderRNA *brna, const char *struct_name
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE);
parm = RNA_def_property(func, "index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Index", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "result", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "NodeInternalSocketTemplate");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
if (def_func)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 0e735350e05..1f018a6ddfc 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -432,11 +432,7 @@ static void rna_Object_parent_set(PointerRNA *ptr, PointerRNA value)
{
Object *ob = (Object *)ptr->data;
Object *par = (Object *)value.data;
-
-#ifdef FREE_WINDOWS
- /* NOTE: this dummy check here prevents this method causing weird runtime errors on mingw 4.6.2 */
- if (ob)
-#endif
+
{
ED_object_parent(ob, par, ob->partype, ob->parsubstr);
}
@@ -532,8 +528,9 @@ static void rna_Object_dup_group_set(PointerRNA *ptr, PointerRNA value)
* thus causing a cycle/infinite-recursion leading to crashes on load [#25298]
*/
if (BKE_group_object_exists(grp, ob) == 0) {
+ id_us_min(&ob->dup_group->id);
ob->dup_group = grp;
- id_lib_extern((ID *)grp);
+ id_us_plus(&ob->dup_group->id);
}
else {
BKE_report(NULL, RPT_ERROR,
@@ -1321,8 +1318,12 @@ static void rna_Object_active_constraint_set(PointerRNA *ptr, PointerRNA value)
static bConstraint *rna_Object_constraints_new(Object *object, int type)
{
+ bConstraint *new_con = BKE_constraint_add_for_object(object, NULL, type);
+
+ ED_object_constraint_tag_update(object, new_con);
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, object);
- return BKE_constraint_add_for_object(object, NULL, type);
+
+ return new_con;
}
static void rna_Object_constraints_remove(Object *object, ReportList *reports, PointerRNA *con_ptr)
@@ -1521,6 +1522,7 @@ static void rna_def_vertex_group(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
FunctionRNA *func;
+ PropertyRNA *parm;
static EnumPropertyItem assign_mode_items[] = {
{WEIGHT_REPLACE, "REPLACE", 0, "Replace", "Replace"},
@@ -1556,27 +1558,27 @@ static void rna_def_vertex_group(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Add vertices to the group");
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
/* TODO, see how array size of 0 works, this shouldnt be used */
- prop = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0);
- RNA_def_property_flag(prop, PROP_DYNAMIC | PROP_REQUIRED);
- prop = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_enum(func, "type", assign_mode_items, 0, "", "Vertex assign mode");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
+ parm = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum(func, "type", assign_mode_items, 0, "", "Vertex assign mode");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "remove", "rna_VertexGroup_vertex_remove");
RNA_def_function_ui_description(func, "Remove a vertex from the group");
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
/* TODO, see how array size of 0 works, this shouldnt be used */
- prop = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0);
- RNA_def_property_flag(prop, PROP_DYNAMIC | PROP_REQUIRED);
+ parm = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
func = RNA_def_function(srna, "weight", "rna_VertexGroup_weight");
RNA_def_function_ui_description(func, "Get a vertex weight from the group");
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
- prop = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "The index of the vertex", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f);
- RNA_def_function_return(func, prop);
+ parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "The index of the vertex", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f);
+ RNA_def_function_return(func, parm);
}
static void rna_def_material_slot(BlenderRNA *brna)
@@ -1955,7 +1957,7 @@ static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a new constraint to this object");
/* object to add */
parm = RNA_def_enum(func, "type", rna_enum_constraint_type_items, 1, "", "Constraint type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "New constraint");
RNA_def_function_return(func, parm);
@@ -1965,8 +1967,8 @@ static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
/* constraint to remove */
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "Removed constraint");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "clear", "rna_Object_constraints_clear");
RNA_def_function_ui_description(func, "Remove all constraint from this object");
@@ -2003,10 +2005,10 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new modifier");
parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the modifier");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* modifier to add */
parm = RNA_def_enum(func, "type", rna_enum_object_modifier_type_items, 1, "", "Modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "modifier", "Modifier", "", "Newly created modifier");
RNA_def_function_return(func, parm);
@@ -2017,8 +2019,8 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove an existing modifier from the object");
/* modifier to remove */
parm = RNA_def_pointer(func, "modifier", "Modifier", "", "Modifier 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* clear all modifiers */
func = RNA_def_function(srna, "clear", "rna_Object_modifier_clear");
@@ -2099,8 +2101,8 @@ static void rna_def_object_vertex_groups(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Delete vertex group from object");
parm = RNA_def_pointer(func, "group", "VertexGroup", "", "Vertex 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "clear", "rna_Object_vgroup_clear");
RNA_def_function_ui_description(func, "Delete all vertex groups from object");
@@ -2390,7 +2392,7 @@ static void rna_def_object(BlenderRNA *brna)
/* 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_range(prop, 0.0f, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(prop, "Dimensions", "Absolute bounding box dimensions of the object");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2892,6 +2894,10 @@ static void rna_def_dupli_object(BlenderRNA *brna)
RNA_def_property_enum_items(prop, dupli_items);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Dupli Type", "Duplicator type that generated this dupli object");
+
+ prop = RNA_def_property(srna, "random_id", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Dupli random id", "Random id for this dupli object");
}
static void rna_def_object_base(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index b66556109e6..9b9f0705bb4 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -321,49 +321,55 @@ static void rna_Object_ray_cast(
float origin[3], float direction[3], float distance,
int *r_success, float r_location[3], float r_normal[3], int *r_index)
{
- BVHTreeFromMesh treeData = {NULL};
-
+ bool success = false;
+
if (ob->derivedFinal == NULL) {
BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for ray casting", ob->id.name + 2);
return;
}
- /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
- bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6);
+ /* Test BoundBox first (efficiency) */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ float distmin;
+ if (!bb || (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, NULL) && distmin <= distance)) {
- /* may fail if the mesh has no faces, in that case the ray-cast misses */
- if (treeData.tree != NULL) {
- BVHTreeRayHit hit;
+ BVHTreeFromMesh treeData = {NULL};
- hit.index = -1;
- hit.dist = distance;
-
- normalize_v3(direction);
+ /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
+ bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6);
+
+ /* may fail if the mesh has no faces, in that case the ray-cast misses */
+ if (treeData.tree != NULL) {
+ BVHTreeRayHit hit;
+ hit.index = -1;
+ hit.dist = distance;
- if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit,
- treeData.raycast_callback, &treeData) != -1)
- {
- if (hit.dist <= distance) {
- *r_success = true;
+ normalize_v3(direction);
- copy_v3_v3(r_location, hit.co);
- copy_v3_v3(r_normal, hit.no);
- *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]);
- goto finally;
+ if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit,
+ treeData.raycast_callback, &treeData) != -1)
+ {
+ if (hit.dist <= distance) {
+ *r_success = success = true;
+
+ copy_v3_v3(r_location, hit.co);
+ copy_v3_v3(r_normal, hit.no);
+ *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]);
+ }
}
+
+ free_bvhtree_from_mesh(&treeData);
}
}
+ if (success == false) {
+ *r_success = false;
- *r_success = false;
-
- zero_v3(r_location);
- zero_v3(r_normal);
- *r_index = -1;
-
-finally:
- free_bvhtree_from_mesh(&treeData);
+ zero_v3(r_location);
+ zero_v3(r_normal);
+ *r_index = -1;
+ }
}
static void rna_Object_closest_point_on_mesh(
@@ -540,28 +546,28 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_ui_description(func, "Compute the coordinate (and scale for ortho cameras) "
"given object should be to 'see' all given coordinates");
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to get render size information from, if available");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float_array(func, "coordinates", 1, NULL, -FLT_MAX, FLT_MAX, "", "Coordinates to fit in",
-FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_DYNAMIC);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL | PROP_DYNAMIC, PARM_REQUIRED);
parm = RNA_def_property(func, "co_return", PROP_FLOAT, PROP_XYZ);
RNA_def_property_array(parm, 3);
RNA_def_property_ui_text(parm, "", "The location to aim to be able to see all given points");
- RNA_def_property_flag(parm, PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, 0, PARM_OUTPUT);
parm = RNA_def_property(func, "scale_return", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(parm, "", "The ortho scale to aim to be able to see all given points (if relevant)");
- RNA_def_property_flag(parm, PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, 0, PARM_OUTPUT);
/* mesh */
func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh");
RNA_def_function_ui_description(func, "Create a Mesh data-block with modifiers applied");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "calc_tessface", true, "Calculate Tessellation", "Calculate tessellation faces");
RNA_def_boolean(func, "calc_undeformed", false, "Calculate Undeformed", "Calculate undeformed vertex coordinates");
parm = RNA_def_pointer(func, "mesh", "Mesh", "",
@@ -574,7 +580,7 @@ void RNA_api_object(StructRNA *srna)
"be freed manually with free_dupli_list to restore the "
"objects real matrix and layers");
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate duplis");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
RNA_def_enum(func, "settings", dupli_eval_mode_items, 0, "", "Generate texture coordinates for rendering");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
@@ -594,15 +600,15 @@ void RNA_api_object(StructRNA *srna)
RNA_def_string(func, "name", "Key", 0, "", "Unique name for the new keyblock"); /* optional */
RNA_def_boolean(func, "from_mix", 1, "", "Create new shape from existing mix of shapes");
parm = RNA_def_pointer(func, "key", "ShapeKey", "", "New shape keyblock");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "shape_key_remove", "rna_Object_shape_key_remove");
RNA_def_function_ui_description(func, "Remove a Shape Key from this object");
RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "key", "ShapeKey", "", "Keyblock to be removed");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* Ray Cast */
func = RNA_def_function(srna, "ray_cast", "rna_Object_ray_cast");
@@ -611,9 +617,9 @@ void RNA_api_object(StructRNA *srna)
/* ray start and end */
parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_float(func, "distance", BVH_RAYCAST_DIST_MAX, 0.0, BVH_RAYCAST_DIST_MAX,
"", "Maximum distance", 0.0, BVH_RAYCAST_DIST_MAX);
@@ -622,11 +628,11 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
"The hit location of this ray cast", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal",
"The face normal at the ray cast hit location", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0);
RNA_def_function_output(func, parm);
@@ -638,7 +644,7 @@ void RNA_api_object(StructRNA *srna)
/* location of point for test and max distance */
parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* default is sqrt(FLT_MAX) */
RNA_def_float(func, "distance", 1.844674352395373e+19, 0.0, FLT_MAX, "", "Maximum distance", 0.0, FLT_MAX);
@@ -647,11 +653,11 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
"The location on the object closest to the point", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal",
"The face normal at the closest point", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0);
@@ -661,7 +667,7 @@ void RNA_api_object(StructRNA *srna)
func = RNA_def_function(srna, "is_visible", "rna_Object_is_visible");
RNA_def_function_ui_description(func, "Determine if object is visible in a given scene");
parm = RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "", "Object visibility");
RNA_def_function_return(func, parm);
@@ -669,18 +675,18 @@ void RNA_api_object(StructRNA *srna)
func = RNA_def_function(srna, "is_modified", "rna_Object_is_modified");
RNA_def_function_ui_description(func, "Determine if this object is modified from the base mesh data");
parm = RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "", "Object visibility");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "is_deform_modified", "rna_Object_is_deform_modified");
RNA_def_function_ui_description(func, "Determine if this object is modified by a deformation from the base mesh data");
parm = RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "", "Object visibility");
RNA_def_function_return(func, parm);
@@ -690,10 +696,10 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_ui_description(func, "Returns a string for derived mesh data");
parm = RNA_def_enum(func, "type", mesh_dm_info_items, 0, "", "Modifier settings to apply");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* weak!, no way to return dynamic string type */
parm = RNA_def_string(func, "result", NULL, 16384, "result", "");
- RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
#endif /* NDEBUG */
@@ -716,7 +722,7 @@ void RNA_api_object_base(StructRNA *srna)
RNA_def_function_ui_description(func,
"Sets the object layers from a 3D View (use when adding an object in local view)");
parm = RNA_def_pointer(func, "view", "SpaceView3D", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
}
#endif /* RNA_RUNTIME */
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 1d89f7535c4..514fca1b011 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -1275,7 +1275,7 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff_power", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_power");
RNA_def_property_range(prop, 0.0f, 10.0f);
- RNA_def_property_ui_text(prop, "Falloff Power", "Falloff power (real gravitational falloff = 2)");
+ RNA_def_property_ui_text(prop, "Falloff Power", "");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
prop = RNA_def_property(srna, "distance_min", PROP_FLOAT, PROP_NONE);
@@ -1394,6 +1394,11 @@ static void rna_def_field(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_SMOKE_DENSITY);
RNA_def_property_ui_text(prop, "Apply Density", "Adjust force strength based on smoke density");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
+ prop = RNA_def_property(srna, "use_gravity_falloff", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_GRAVITATION);
+ RNA_def_property_ui_text(prop, "Gravity Falloff", "Multiply force by 1/distance²");
+ RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
+
/* Pointer */
diff --git a/source/blender/makesrna/intern/rna_palette.c b/source/blender/makesrna/intern/rna_palette.c
index 8cbb57fde2c..4d6b94bf709 100644
--- a/source/blender/makesrna/intern/rna_palette.c
+++ b/source/blender/makesrna/intern/rna_palette.c
@@ -115,8 +115,8 @@ static void rna_def_palettecolors(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a color from the palette");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "color", "PaletteColor", "", "The color 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "clear", "rna_Palette_color_clear");
RNA_def_function_ui_description(func, "Remove all colors from the palette");
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 5e3fa4b467d..00104b8667d 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -45,6 +45,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "BLI_string_utils.h"
+
#include "BLT_translation.h"
#include "rna_internal.h"
@@ -444,10 +446,12 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
int totpart;
int totchild = 0;
int totface;
+ int totvert;
int num = -1;
DM_ensure_tessface(modifier->dm_final); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
totface = modifier->dm_final->getNumTessFaces(modifier->dm_final);
+ totvert = modifier->dm_final->getNumVerts(modifier->dm_final);
/* 1. check that everything is ok & updated */
if (!particlesystem || !totface) {
@@ -482,13 +486,29 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
return num;
}
}
+ else if (part->from == PART_FROM_VERT) {
+ if (num != DMCACHE_NOTFOUND && num < totvert) {
+ MFace *mface = modifier->dm_final->getTessFaceDataArray(modifier->dm_final, CD_MFACE);
+
+ *r_fuv = &particle->fuv;
+
+ /* This finds the first face to contain the emitting vertex,
+ * this is not ideal, but is mostly fine as UV seams generally
+ * map to equal-colored parts of a texture */
+ for (int i = 0; i < totface; i++, mface++) {
+ if (ELEM(num, mface->v1, mface->v2, mface->v3, mface->v4)) {
+ return i;
+ }
+ }
+ }
+ }
}
else {
ChildParticle *cpa = particlesystem->child + particle_no - totpart;
num = cpa->num;
if (part->childtype == PART_CHILD_FACES) {
- if (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ if (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME, PART_FROM_VERT)) {
if (num != DMCACHE_NOTFOUND && num < totface) {
*r_fuv = &cpa->fuv;
return num;
@@ -508,6 +528,22 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
return num;
}
}
+ else if (part->from == PART_FROM_VERT) {
+ if (num != DMCACHE_NOTFOUND && num < totvert) {
+ MFace *mface = modifier->dm_final->getTessFaceDataArray(modifier->dm_final, CD_MFACE);
+
+ *r_fuv = &parent->fuv;
+
+ /* This finds the first face to contain the emitting vertex,
+ * this is not ideal, but is mostly fine as UV seams generally
+ * map to equal-colored parts of a texture */
+ for (int i = 0; i < totface; i++, mface++) {
+ if (ELEM(num, mface->v1, mface->v2, mface->v3, mface->v4)) {
+ return i;
+ }
+ }
+ }
+ }
}
}
@@ -1295,7 +1331,9 @@ static void rna_def_particle_hair_key(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
srna = RNA_def_struct(brna, "ParticleHairKey", NULL);
RNA_def_struct_sdna(srna, "HairKey");
@@ -1323,18 +1361,16 @@ static void rna_def_particle_hair_key(BlenderRNA *brna)
/* Aided co func */
func = RNA_def_function(srna, "co_object", "rna_ParticleHairKey_co_object");
RNA_def_function_ui_description(func, "Obtain hairkey location with particle and modifier data");
-
- prop = RNA_def_pointer(func, "object", "Object", "", "Object");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_pointer(func, "particle", "Particle", "", "hair particle");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
-
- prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
+ parm = RNA_def_pointer(func, "object", "Object", "", "Object");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "particle", "Particle", "", "hair particle");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
"Exported hairkey location", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
}
static void rna_def_particle_key(BlenderRNA *brna)
@@ -1386,7 +1422,9 @@ static void rna_def_particle(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
static EnumPropertyItem alive_items[] = {
/*{PARS_KILLED, "KILLED", 0, "Killed", ""}, */
@@ -1496,12 +1534,12 @@ static void rna_def_particle(BlenderRNA *brna)
func = RNA_def_function(srna, "uv_on_emitter", "rna_Particle_uv_on_emitter");
RNA_def_function_ui_description(func, "Obtain uv for particle on derived mesh");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_array(prop, 2);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_array(parm, 2);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
}
static void rna_def_particle_dupliweight(BlenderRNA *brna)
@@ -2091,7 +2129,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Even Distribution",
"Use even distribution from faces based on face areas or edge lengths");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
-
+
prop = RNA_def_property(srna, "use_die_on_collision", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_DIE_ON_COL);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -2296,7 +2334,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_render_adaptive", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_REN_ADAPT);
- RNA_def_property_ui_text(prop, "Adaptive render", "Draw steps of the particle path");
+ RNA_def_property_ui_text(prop, "Adaptive Render", "Draw steps of the particle path");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "use_velocity_length", PROP_BOOLEAN, PROP_NONE);
@@ -2311,7 +2349,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_strand_primitive", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_REN_STRAND);
- RNA_def_property_ui_text(prop, "Strand render", "Use the strand primitive for rendering");
+ RNA_def_property_ui_text(prop, "Strand Render", "Use the strand primitive for rendering");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "draw_method", PROP_ENUM, PROP_NONE);
@@ -2359,7 +2397,8 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Render", "How many steps paths are rendered with (power of 2)");
prop = RNA_def_property(srna, "hair_step", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 2, 50);
+ RNA_def_property_range(prop, 2, SHRT_MAX);
+ RNA_def_property_ui_range(prop, 2, 50, 1, 1);
RNA_def_property_ui_text(prop, "Segments", "Number of hair segments");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
@@ -3194,7 +3233,9 @@ static void rna_def_particle_system(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
static EnumPropertyItem resolution_items[] = {
{eModifierMode_Realtime, "PREVIEW", 0, "Preview", "Apply modifier preview settings"},
@@ -3503,53 +3544,51 @@ static void rna_def_particle_system(BlenderRNA *brna)
/* set viewport or render resolution */
func = RNA_def_function(srna, "set_resolution", "rna_ParticleSystem_set_resolution");
RNA_def_function_ui_description(func, "Set the resolution to use for the number of particles");
- prop = RNA_def_pointer(func, "scene", "Scene", "", "Scene");
- prop = RNA_def_pointer(func, "object", "Object", "", "Object");
- prop = RNA_def_enum(func, "resolution", resolution_items, 0, "", "Resolution settings to apply");
+ RNA_def_pointer(func, "scene", "Scene", "", "Scene");
+ RNA_def_pointer(func, "object", "Object", "", "Object");
+ RNA_def_enum(func, "resolution", resolution_items, 0, "", "Resolution settings to apply");
/* extract cached hair location data */
func = RNA_def_function(srna, "co_hair", "rna_ParticleSystem_co_hair");
RNA_def_function_ui_description(func, "Obtain cache hair data");
-
- prop = RNA_def_pointer(func, "object", "Object", "", "Object");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
- prop = RNA_def_int(func, "step", 0, INT_MIN, INT_MAX, "step no", "", INT_MIN, INT_MAX);
-
- prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
+ parm = RNA_def_pointer(func, "object", "Object", "", "Object");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
+ RNA_def_int(func, "step", 0, INT_MIN, INT_MAX, "step no", "", INT_MIN, INT_MAX);
+ parm = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
"Exported hairkey location", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
/* extract hair UVs */
func = RNA_def_function(srna, "uv_on_emitter", "rna_ParticleSystem_uv_on_emitter");
RNA_def_function_ui_description(func, "Obtain uv for all particles");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
- prop = RNA_def_int(func, "uv_no", 0, INT_MIN, INT_MAX, "UV no", "", INT_MIN, INT_MAX);
- prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_array(prop, 2);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
+ RNA_def_int(func, "uv_no", 0, INT_MIN, INT_MAX, "UV no", "", INT_MIN, INT_MAX);
+ parm = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_array(parm, 2);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
/* extract hair mcols */
func = RNA_def_function(srna, "mcol_on_emitter", "rna_ParticleSystem_mcol_on_emitter");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Obtain mcol for all particles");
- prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
- prop = RNA_def_int(func, "vcol_no", 0, INT_MIN, INT_MAX, "vcol no", "", INT_MIN, INT_MAX);
- prop = RNA_def_property(func, "mcol", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 3);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "particle", "Particle", "", "Particle");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
+ RNA_def_int(func, "vcol_no", 0, INT_MIN, INT_MAX, "vcol no", "", INT_MIN, INT_MAX);
+ parm = RNA_def_property(func, "mcol", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_array(parm, 3);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 0591e877634..8d161466d56 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -40,6 +40,7 @@
#include "DNA_scene_types.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -523,12 +524,15 @@ static void rna_PoseChannel_active_constraint_set(PointerRNA *ptr, PointerRNA va
BKE_constraints_active_set(&pchan->constraints, (bConstraint *)value.data);
}
-static bConstraint *rna_PoseChannel_constraints_new(bPoseChannel *pchan, int type)
+static bConstraint *rna_PoseChannel_constraints_new(ID *id, bPoseChannel *pchan, Main *main, int type)
{
- /*WM_main_add_notifier(NC_OBJECT|ND_CONSTRAINT|NA_ADDED, object); */
- /* TODO, pass object also */
- /* TODO, new pose bones don't have updated draw flags */
- return BKE_constraint_add_for_pose(NULL, pchan, NULL, type);
+ Object *ob = (Object *)id;
+ bConstraint *new_con = BKE_constraint_add_for_pose(ob, pchan, NULL, type);
+
+ ED_object_constraint_dependency_tag_update(main, ob, new_con);
+ WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, id);
+
+ return new_con;
}
static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, ReportList *reports, PointerRNA *con_ptr)
@@ -763,20 +767,21 @@ static void rna_def_pose_channel_constraints(BlenderRNA *brna, PropertyRNA *cpro
/* Constraint collection */
func = RNA_def_function(srna, "new", "rna_PoseChannel_constraints_new");
RNA_def_function_ui_description(func, "Add a constraint to this object");
+ RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_SELF_ID); /* ID and Main needed for refresh */
/* return type */
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "New constraint");
RNA_def_function_return(func, parm);
/* constraint to add */
parm = RNA_def_enum(func, "type", rna_enum_constraint_type_items, 1, "", "Constraint type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "remove", "rna_PoseChannel_constraints_remove");
RNA_def_function_ui_description(func, "Remove a constraint from this object");
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); /* ID needed for refresh */
/* constraint to remove */
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "Removed constraint");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_pose_channel(BlenderRNA *brna)
@@ -1359,8 +1364,8 @@ static void rna_def_bone_groups(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); /* ID needed for refresh */
/* bone group to remove */
parm = RNA_def_pointer(func, "group", "BoneGroup", "", "Removed bone group");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "BoneGroup");
diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c
index 465a86adc31..f523b725b18 100644
--- a/source/blender/makesrna/intern/rna_pose_api.c
+++ b/source/blender/makesrna/intern/rna_pose_api.c
@@ -76,7 +76,7 @@ void RNA_api_pose_channel(StructRNA *srna)
RNA_def_function_ui_description(func, "Calculate bone envelope at given point");
parm = RNA_def_float_vector_xyz(func, "point", 3, NULL, -FLT_MAX, FLT_MAX, "Point",
"Position in 3d space to evaluate", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return value */
parm = RNA_def_float(func, "factor", 0, -FLT_MAX, FLT_MAX, "Factor", "Envelope factor", -FLT_MAX, FLT_MAX);
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_property.c b/source/blender/makesrna/intern/rna_property.c
index 07bdbb03357..fb70870f49b 100644
--- a/source/blender/makesrna/intern/rna_property.c
+++ b/source/blender/makesrna/intern/rna_property.c
@@ -31,6 +31,7 @@
#include "DNA_object_types.h"
#include "BLI_path_util.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 84382704b2b..034782cc818 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -26,12 +26,15 @@
#include <stdlib.h>
+#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
+#include "BKE_scene.h"
+
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -40,7 +43,9 @@
#include "RE_engine.h"
#include "RE_pipeline.h"
+#include "ED_render.h"
+/* Deprecated, only provided for API compatibility. */
EnumPropertyItem rna_enum_render_pass_type_items[] = {
{SCE_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
{SCE_PASS_Z, "Z", 0, "Z", ""},
@@ -77,13 +82,6 @@ EnumPropertyItem rna_enum_render_pass_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem rna_enum_render_pass_debug_type_items[] = {
- {RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS, "BVH_TRAVERSAL_STEPS", 0, "BVH Traversal Steps", ""},
- {RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES, "BVH_TRAVERSED_INSTANCES", 0, "BVH Traversed Instances", ""},
- {RENDER_PASS_DEBUG_RAY_BOUNCES, "RAY_BOUNCES", 0, "Ray Steps", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
EnumPropertyItem rna_enum_bake_pass_type_items[] = {
{SCE_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
{SCE_PASS_AO, "AO", 0, "AO", ""},
@@ -128,6 +126,11 @@ static int engine_support_display_space_shader(RenderEngine *UNUSED(engine), Sce
return IMB_colormanagement_support_glsl_draw(&scene->view_settings);
}
+static int engine_get_preview_pixel_size(RenderEngine *UNUSED(engine), Scene *scene)
+{
+ return BKE_render_preview_pixel_size(&scene->r);
+}
+
static void engine_bind_display_space_shader(RenderEngine *UNUSED(engine), Scene *scene)
{
IMB_colormanagement_setup_glsl_draw(&scene->view_settings,
@@ -256,9 +259,27 @@ static void engine_update_script_node(RenderEngine *engine, struct bNodeTree *nt
RNA_parameter_list_free(&list);
}
+static void engine_update_render_passes(RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl)
+{
+ extern FunctionRNA rna_RenderEngine_update_render_passes_func;
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
+ func = &rna_RenderEngine_update_render_passes_func;
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "scene", &scene);
+ RNA_parameter_set_lookup(&list, "renderlayer", &srl);
+ engine->type->ext.call(NULL, &ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
/* RenderEngine registration */
-static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type)
+static void rna_RenderEngine_unregister(Main *bmain, StructRNA *type)
{
RenderEngineType *et = RNA_struct_blender_type_get(type);
@@ -266,17 +287,21 @@ static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
RNA_struct_free_extension(type, &et->ext);
- BLI_freelinkN(&R_engines, et);
RNA_struct_free(&BLENDER_RNA, type);
+ BLI_freelinkN(&R_engines, et);
+
+ /* Stop all renders in case we were using this one. */
+ ED_render_engine_changed(bmain);
}
-static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_RenderEngine_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
RenderEngineType *et, dummyet = {NULL};
RenderEngine dummyengine = {NULL};
PointerRNA dummyptr;
- int have_function[6];
+ int have_function[7];
/* setup dummy engine & engine type to store static properties in */
dummyengine.type = &dummyet;
@@ -318,6 +343,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
et->view_update = (have_function[3]) ? engine_view_update : NULL;
et->view_draw = (have_function[4]) ? engine_view_draw : NULL;
et->update_script_node = (have_function[5]) ? engine_update_script_node : NULL;
+ et->update_render_passes = (have_function[6]) ? engine_update_render_passes : NULL;
BLI_addtail(&R_engines, et);
@@ -414,14 +440,28 @@ static RenderPass *rna_RenderPass_find_by_type(RenderLayer *rl, int passtype, co
return RE_pass_find_by_type(rl, passtype, view);
}
+static RenderPass *rna_RenderPass_find_by_name(RenderLayer *rl, const char *name, const char *view)
+{
+ return RE_pass_find_by_name(rl, name, view);
+}
+
#else /* RNA_RUNTIME */
static void rna_def_render_engine(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
-
+ PropertyRNA *parm;
+
+ static EnumPropertyItem render_pass_type_items[] = {
+ {SOCK_FLOAT, "VALUE", 0, "Value", ""},
+ {SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
+ {SOCK_RGBA, "COLOR", 0, "Color", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "RenderEngine", NULL);
RNA_def_struct_sdna(srna, "RenderEngine");
RNA_def_struct_ui_text(srna, "Render Engine", "Render engine");
@@ -444,25 +484,25 @@ static void rna_def_render_engine(BlenderRNA *brna)
func = RNA_def_function(srna, "bake", NULL);
RNA_def_function_ui_description(func, "Bake passes");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
- prop = RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_pointer(func, "object", "Object", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_enum(func, "pass_type", rna_enum_bake_pass_type_items, 0, "Pass", "Pass to bake");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "pass_filter", 0, 0, INT_MAX, "Pass Filter", "Filter to combined, diffuse, glossy, transmission and subsurface passes", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "object_id", 0, 0, INT_MAX, "Object Id", "Id of the current object being baked in relation to the others", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_pointer(func, "pixel_array", "BakePixel", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "num_pixels", 0, 0, INT_MAX, "Number of Pixels", "Size of the baking batch", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "depth", 0, 0, INT_MAX, "Pixels depth", "Number of channels", 1, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "object", "Object", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum(func, "pass_type", rna_enum_bake_pass_type_items, 0, "Pass", "Pass to bake");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "pass_filter", 0, 0, INT_MAX, "Pass Filter", "Filter to combined, diffuse, glossy, transmission and subsurface passes", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "object_id", 0, 0, INT_MAX, "Object Id", "Id of the current object being baked in relation to the others", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "pixel_array", "BakePixel", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "num_pixels", 0, 0, INT_MAX, "Number of Pixels", "Size of the baking batch", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "depth", 0, 0, INT_MAX, "Pixels depth", "Number of channels", 1, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* TODO, see how array size of 0 works, this shouldnt be used */
- prop = RNA_def_pointer(func, "result", "AnyType", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "AnyType", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* viewport render callbacks */
func = RNA_def_function(srna, "view_update", NULL);
@@ -479,8 +519,8 @@ static void rna_def_render_engine(BlenderRNA *brna)
func = RNA_def_function(srna, "update_script_node", NULL);
RNA_def_function_ui_description(func, "Compile shader script node");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
- prop = RNA_def_pointer(func, "node", "Node", "", "");
- RNA_def_property_flag(prop, PROP_RNAPTR);
+ parm = RNA_def_pointer(func, "node", "Node", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
/* tag for redraw */
func = RNA_def_function(srna, "tag_redraw", "engine_tag_redraw");
@@ -490,117 +530,141 @@ static void rna_def_render_engine(BlenderRNA *brna)
func = RNA_def_function(srna, "tag_update", "engine_tag_update");
RNA_def_function_ui_description(func, "Request update call for viewport rendering");
+ func = RNA_def_function(srna, "update_render_passes", NULL);
+ RNA_def_function_ui_description(func, "Update the render passes that will be generated");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ parm = RNA_def_pointer(func, "renderlayer", "SceneRenderLayer", "", "");
+
func = RNA_def_function(srna, "begin_result", "RE_engine_begin_result");
RNA_def_function_ui_description(func, "Create render result to write linear floating point render layers and passes");
- prop = RNA_def_int(func, "x", 0, 0, INT_MAX, "X", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "y", 0, 0, INT_MAX, "Y", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "w", 0, 0, INT_MAX, "Width", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "h", 0, 0, INT_MAX, "Height", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_int(func, "x", 0, 0, INT_MAX, "X", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "y", 0, 0, INT_MAX, "Y", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "w", 0, 0, INT_MAX, "Width", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "h", 0, 0, INT_MAX, "Height", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_string(func, "layer", NULL, 0, "Layer", "Single layer to get render result for"); /* NULL ok here */
RNA_def_string(func, "view", NULL, 0, "View", "Single view to get render result for"); /* NULL ok here */
- prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
+ RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "update_result", "RE_engine_update_result");
RNA_def_function_ui_description(func, "Signal that pixels have been updated and can be redrawn in the user interface");
- prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "end_result", "RE_engine_end_result");
RNA_def_function_ui_description(func, "All pixels in the render result have been set and are final");
- prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "cancel", 0, "Cancel", "Don't mark tile as done, don't merge results unless forced");
+ RNA_def_boolean(func, "highlight", 0, "Highlight", "Don't mark tile as done yet");
RNA_def_boolean(func, "do_merge_results", 0, "Merge Results", "Merge results even if cancel=true");
+ func = RNA_def_function(srna, "add_pass", "RE_engine_add_pass");
+ RNA_def_function_ui_description(func, "Add a pass to the render layer");
+ parm = RNA_def_string(func, "name", NULL, 0, "Name", "Name of the Pass, without view or channel tag");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "channels", 0, 0, INT_MAX, "Channels", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "chan_id", NULL, 0, "Channel IDs", "Channel names, one character per channel");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_string(func, "layer", NULL, 0, "Layer", "Single layer to add render pass to"); /* NULL ok here */
+
+
func = RNA_def_function(srna, "test_break", "RE_engine_test_break");
RNA_def_function_ui_description(func, "Test if the render operation should been canceled, this is a fast call that should be used regularly for responsiveness");
- prop = RNA_def_boolean(func, "do_break", 0, "Break", "");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_boolean(func, "do_break", 0, "Break", "");
+ RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "active_view_get", "RE_engine_active_view_get");
- prop = RNA_def_string(func, "view", NULL, 0, "View", "Single view active");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_string(func, "view", NULL, 0, "View", "Single view active");
+ RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "active_view_set", "RE_engine_active_view_set");
- RNA_def_string(func, "view", NULL, 0, "View", "Single view to set as active"); /* NULL ok here */
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_string(func, "view", NULL, 0, "View", "Single view to set as active"); /* NULL ok here */
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "camera_shift_x", "RE_engine_get_camera_shift_x");
- prop = RNA_def_pointer(func, "camera", "Object", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
- prop = RNA_def_float(func, "shift_x", 0.0f, 0.0f, FLT_MAX, "Shift X", "", 0.0f, FLT_MAX);
- RNA_def_function_return(func, prop);
+ parm = RNA_def_pointer(func, "camera", "Object", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
+ parm = RNA_def_float(func, "shift_x", 0.0f, 0.0f, FLT_MAX, "Shift X", "", 0.0f, FLT_MAX);
+ RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "camera_model_matrix", "RE_engine_get_camera_model_matrix");
- prop = RNA_def_pointer(func, "camera", "Object", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
- prop = RNA_def_float_matrix(func, "r_model_matrix", 4, 4, NULL, 0.0f, 0.0f, "Model Matrix", "Normalized camera model matrix", 0.0f, 0.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "camera", "Object", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
+ parm = RNA_def_float_matrix(func, "r_model_matrix", 4, 4, NULL, 0.0f, 0.0f, "Model Matrix", "Normalized camera model matrix", 0.0f, 0.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "use_spherical_stereo", "RE_engine_get_spherical_stereo");
- prop = RNA_def_pointer(func, "camera", "Object", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_pointer(func, "camera", "Object", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
+ RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "update_stats", "RE_engine_update_stats");
RNA_def_function_ui_description(func, "Update and signal to redraw render status text");
- prop = RNA_def_string(func, "stats", NULL, 0, "Stats", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_string(func, "info", NULL, 0, "Info", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_string(func, "stats", NULL, 0, "Stats", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "info", NULL, 0, "Info", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "frame_set", "RE_engine_frame_set");
RNA_def_function_ui_description(func, "Evaluate scene at a different frame (for motion blur)");
- prop = RNA_def_int(func, "frame", 0, INT_MIN, INT_MAX, "Frame", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_float(func, "subframe", 0.0f, 0.0f, 1.0f, "Subframe", "", 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_int(func, "frame", 0, INT_MIN, INT_MAX, "Frame", "", INT_MIN, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float(func, "subframe", 0.0f, 0.0f, 1.0f, "Subframe", "", 0.0f, 1.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "update_progress", "RE_engine_update_progress");
RNA_def_function_ui_description(func, "Update progress percentage of render");
- prop = RNA_def_float(func, "progress", 0, 0.0f, 1.0f, "", "Percentage of render that's done", 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_float(func, "progress", 0, 0.0f, 1.0f, "", "Percentage of render that's done", 0.0f, 1.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "update_memory_stats", "RE_engine_update_memory_stats");
RNA_def_function_ui_description(func, "Update memory usage statistics");
RNA_def_float(func, "memory_used", 0, 0.0f, FLT_MAX, "", "Current memory usage in megabytes", 0.0f, FLT_MAX);
RNA_def_float(func, "memory_peak", 0, 0.0f, FLT_MAX, "", "Peak memory usage in megabytes", 0.0f, FLT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
func = RNA_def_function(srna, "report", "RE_engine_report");
RNA_def_function_ui_description(func, "Report info, warning or error messages");
- prop = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "error_set", "RE_engine_set_error_message");
RNA_def_function_ui_description(func, "Set error message displaying after the render is finished");
- prop = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "bind_display_space_shader", "engine_bind_display_space_shader");
RNA_def_function_ui_description(func, "Bind GLSL fragment shader that converts linear colors to display space colors using scene color management settings");
- prop = RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "unbind_display_space_shader", "engine_unbind_display_space_shader");
RNA_def_function_ui_description(func, "Unbind GLSL display space shader, must always be called after binding the shader");
func = RNA_def_function(srna, "support_display_space_shader", "engine_support_display_space_shader");
RNA_def_function_ui_description(func, "Test if GLSL display space shader is supported for the combination of graphics card and scene settings");
- prop = RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_boolean(func, "supported", 0, "Supported", "");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "supported", 0, "Supported", "");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "get_preview_pixel_size", "engine_get_preview_pixel_size");
+ RNA_def_function_ui_description(func, "Get the pixel size that should be used for preview rendering");
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "pixel_size", 0, 1, 8, "Pixel Size", "", 1, 8);
+ RNA_def_function_return(func, parm);
RNA_define_verify_sdna(0);
@@ -640,6 +704,21 @@ static void rna_def_render_engine(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_highlight_tiles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RE_ENGINE_HIGHLIGHT_TILES);
+ func = RNA_def_function(srna, "register_pass", "RE_engine_register_pass");
+ RNA_def_function_ui_description(func, "Register a render pass that will be part of the render with the current settings");
+ prop = RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ prop = RNA_def_pointer(func, "srl", "SceneRenderLayer", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ prop = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ prop = RNA_def_int(func, "channels", 1, 1, 8, "Channels", "", 1, 4);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ prop = RNA_def_string(func, "chanid", NULL, 8, "Channel IDs", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ prop = RNA_def_enum(func, "type", render_pass_type_items, SOCK_FLOAT, "Type", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
@@ -689,6 +768,8 @@ static void rna_def_render_engine(BlenderRNA *brna)
static void rna_def_render_result(BlenderRNA *brna)
{
StructRNA *srna;
+ PropertyRNA *prop;
+
FunctionRNA *func;
PropertyRNA *parm;
@@ -701,27 +782,27 @@ static void rna_def_render_result(BlenderRNA *brna)
parm = RNA_def_string_file_name(func, "filename", NULL, FILE_MAX, "File Name",
"Filename to load into this render tile, must be no smaller than "
"the render result");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_define_verify_sdna(0);
- parm = RNA_def_property(srna, "resolution_x", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(parm, NULL, "rectx");
- RNA_def_property_clear_flag(parm, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "resolution_x", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "rectx");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- parm = RNA_def_property(srna, "resolution_y", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(parm, NULL, "recty");
- RNA_def_property_clear_flag(parm, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "resolution_y", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "recty");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- parm = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(parm, "RenderLayer");
- RNA_def_property_collection_funcs(parm, "rna_RenderResult_layers_begin", "rna_iterator_listbase_next",
+ prop = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "RenderLayer");
+ RNA_def_property_collection_funcs(prop, "rna_RenderResult_layers_begin", "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
- parm = RNA_def_property(srna, "views", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(parm, "RenderView");
- RNA_def_property_collection_funcs(parm, "rna_RenderResult_views_begin", "rna_iterator_listbase_next",
+ prop = RNA_def_property(srna, "views", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "RenderView");
+ RNA_def_property_collection_funcs(prop, "rna_RenderResult_views_begin", "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
@@ -761,19 +842,29 @@ static void rna_def_render_passes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "find_by_type", "rna_RenderPass_find_by_type");
RNA_def_function_ui_description(func, "Get the render pass for a given type and view");
parm = RNA_def_enum(func, "pass_type", rna_enum_render_pass_type_items, SCE_PASS_COMBINED, "Pass", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "view", NULL, 0, "View", "Render view to get pass from"); /* NULL ok here */
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "render_pass", "RenderPass", "", "The matching render pass");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "find_by_name", "rna_RenderPass_find_by_name");
+ RNA_def_function_ui_description(func, "Get the render pass for a given name and view");
+ parm = RNA_def_string(func, "name", RE_PASSNAME_COMBINED, 0, "Pass", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "view", NULL, 0, "View", "Render view to get pass from"); /* NULL ok here */
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "render_pass", "RenderPass", "", "The matching render pass");
+ RNA_def_function_return(func, parm);
}
static void rna_def_render_layer(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
srna = RNA_def_struct(brna, "RenderLayer", NULL);
RNA_def_struct_ui_text(srna, "Render Layer", "");
@@ -781,9 +872,9 @@ static void rna_def_render_layer(BlenderRNA *brna)
func = RNA_def_function(srna, "load_from_file", "RE_layer_load_from_file");
RNA_def_function_ui_description(func, "Copies the pixels of this renderlayer from an image file");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- prop = RNA_def_string(func, "filename", NULL, 0, "Filename",
+ parm = RNA_def_string(func, "filename", NULL, 0, "Filename",
"Filename to load into this render tile, must be no smaller than the renderlayer");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "x", 0, 0, INT_MAX, "Offset X",
"Offset the position to copy from if the image is larger than the render layer", 0, INT_MAX);
RNA_def_int(func, "y", 0, 0, INT_MAX, "Offset Y",
@@ -813,6 +904,11 @@ static void rna_def_render_pass(BlenderRNA *brna)
RNA_define_verify_sdna(0);
+ prop = RNA_def_property(srna, "fullname", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "fullname");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_struct_name_property(srna, prop);
+
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -826,11 +922,6 @@ static void rna_def_render_pass(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "channels");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "passtype");
- RNA_def_property_enum_items(prop, rna_enum_render_pass_type_items);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
prop = RNA_def_property(srna, "rect", PROP_FLOAT, PROP_NONE);
RNA_def_property_flag(prop, PROP_DYNAMIC);
RNA_def_property_multi_array(prop, 2, NULL);
@@ -841,11 +932,6 @@ static void rna_def_render_pass(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "view_id");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "debug_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "debug_type");
- RNA_def_property_enum_items(prop, rna_enum_render_pass_debug_type_items);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
RNA_define_verify_sdna(1);
}
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index 85a34a94746..a1a7efdaba5 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -730,7 +730,9 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
srna = RNA_def_struct(brna, "RigidBodyWorld", NULL);
RNA_def_struct_sdna(srna, "RigidBodyWorld");
@@ -813,34 +815,28 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
func = RNA_def_function(srna, "convex_sweep_test", "rna_RigidBodyWorld_convex_sweep_test");
RNA_def_function_ui_description(func, "Sweep test convex rigidbody against the current rigidbody world");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
-
- prop = RNA_def_pointer(func, "object", "Object", "", "Rigidbody object with a convex collision shape");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- RNA_def_property_clear_flag(prop, PROP_THICK_WRAP);
-
+ parm = RNA_def_pointer(func, "object", "Object", "", "Rigidbody object with a convex collision shape");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* ray start and end */
- prop = RNA_def_float_vector(func, "start", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_float_vector(func, "end", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_REQUIRED);
-
- prop = RNA_def_float_vector(func, "object_location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
+ parm = RNA_def_float_vector(func, "start", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float_vector(func, "end", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float_vector(func, "object_location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
"The hit location of this sweep test", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
-
- prop = RNA_def_float_vector(func, "hitpoint", 3, NULL, -FLT_MAX, FLT_MAX, "Hitpoint",
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_float_vector(func, "hitpoint", 3, NULL, -FLT_MAX, FLT_MAX, "Hitpoint",
"The hit location of this sweep test", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
-
- prop = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal",
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal",
"The face normal at the sweep test hit location", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
-
- prop = RNA_def_int(func, "has_hit", 0, 0, 0, "", "If the function has found collision point, value is 1, otherwise 0", 0, 0);
- RNA_def_function_output(func, prop);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_int(func, "has_hit", 0, 0, 0, "", "If the function has found collision point, value is 1, otherwise 0", 0, 0);
+ RNA_def_function_output(func, parm);
}
static void rna_def_rigidbody_object(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 727bdac087b..502a9c42363 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -178,7 +178,7 @@ static int rna_idproperty_known(CollectionPropertyIterator *iter, void *data)
* for the second loop where we go over unknown id properties */
do {
for (prop = ptype->cont.properties.first; prop; prop = prop->next)
- if ((prop->flag & PROP_BUILTIN) == 0 && STREQ(prop->identifier, idprop->name))
+ if ((prop->flag_internal & PROP_INTERN_BUILTIN) == 0 && STREQ(prop->identifier, idprop->name))
return 1;
} while ((ptype = ptype->base));
@@ -191,7 +191,7 @@ static int rna_property_builtin(CollectionPropertyIterator *UNUSED(iter), void *
/* function to skip builtin rna properties */
- return (prop->flag & PROP_BUILTIN);
+ return (prop->flag_internal & PROP_INTERN_BUILTIN);
}
static int rna_function_builtin(CollectionPropertyIterator *UNUSED(iter), void *data)
@@ -385,7 +385,7 @@ int rna_builtin_properties_lookup_string(PointerRNA *ptr, const char *key, Point
}
else {
for (prop = srna->cont.properties.first; prop; prop = prop->next) {
- if (!(prop->flag & PROP_BUILTIN) && STREQ(prop->identifier, key)) {
+ if (!(prop->flag_internal & PROP_INTERN_BUILTIN) && STREQ(prop->identifier, key)) {
propptr.type = &RNA_Property;
propptr.data = prop;
@@ -557,19 +557,19 @@ static int rna_Property_animatable_get(PointerRNA *ptr)
static int rna_Property_use_output_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag & PROP_OUTPUT) != 0;
+ return (prop->flag_parameter & PARM_OUTPUT) != 0;
}
static int rna_Property_is_required_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag & PROP_REQUIRED) != 0;
+ return (prop->flag_parameter & PARM_REQUIRED) != 0;
}
static int rna_Property_is_argument_optional_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag & PROP_PYFUNC_OPTIONAL) != 0;
+ return (prop->flag_parameter & PARM_PYFUNC_OPTIONAL) != 0;
}
static int rna_Property_is_never_none_get(PointerRNA *ptr)
@@ -610,6 +610,22 @@ static int rna_Property_array_length_get(PointerRNA *ptr)
return prop->totarraylength;
}
+static void rna_Property_array_dimensions_get(PointerRNA *ptr, int dimensions[RNA_MAX_ARRAY_DIMENSION])
+{
+ PropertyRNA *prop = (PropertyRNA *)ptr->data;
+ rna_idproperty_check(&prop, ptr);
+
+ if (prop->arraydimension > 1) {
+ for (int i = RNA_MAX_ARRAY_DIMENSION; i--; ) {
+ dimensions[i] = (i >= prop->arraydimension) ? 0 : prop->arraylength[i];
+ }
+ }
+ else {
+ memset(dimensions, 0, sizeof(*dimensions) * RNA_MAX_ARRAY_DIMENSION);
+ dimensions[0] = prop->totarraylength;
+ }
+}
+
static int rna_Property_is_registered_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
@@ -625,7 +641,7 @@ static int rna_Property_is_registered_optional_get(PointerRNA *ptr)
static int rna_Property_is_runtime_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag & PROP_RUNTIME) != 0;
+ return (prop->flag_internal & PROP_INTERN_RUNTIME) != 0;
}
@@ -983,21 +999,32 @@ static int rna_Function_use_self_type_get(PointerRNA *ptr)
/* Blender RNA */
+static int rna_struct_is_publc(CollectionPropertyIterator *UNUSED(iter), void *data)
+{
+ StructRNA *srna = data;
+
+ return !(srna->flag & STRUCT_PUBLIC_NAMESPACE);
+}
+
+
static void rna_BlenderRNA_structs_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- rna_iterator_listbase_begin(iter, &((BlenderRNA *)ptr->data)->structs, NULL);
+ BlenderRNA *brna = ptr->data;
+ rna_iterator_listbase_begin(iter, &brna->structs, rna_struct_is_publc);
}
/* optional, for faster lookups */
static int rna_BlenderRNA_structs_length(PointerRNA *ptr)
{
- return BLI_listbase_count(&((BlenderRNA *)ptr->data)->structs);
+ BlenderRNA *brna = ptr->data;
+ BLI_assert(brna->structs_len == BLI_listbase_count(&brna->structs));
+ return brna->structs_len;
}
static int rna_BlenderRNA_structs_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
{
- StructRNA *srna = BLI_findlink(&((BlenderRNA *)ptr->data)->structs, index);
-
- if (srna) {
+ BlenderRNA *brna = ptr->data;
+ StructRNA *srna = index < brna->structs_len ? BLI_findlink(&brna->structs, index) : NULL;
+ if (srna != NULL) {
RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr);
return true;
}
@@ -1007,12 +1034,11 @@ static int rna_BlenderRNA_structs_lookup_int(PointerRNA *ptr, int index, Pointer
}
static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr)
{
- StructRNA *srna = ((BlenderRNA *)ptr->data)->structs.first;
- for (; srna; srna = srna->cont.next) {
- if (key[0] == srna->identifier[0] && STREQ(key, srna->identifier)) {
- RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr);
- return true;
- }
+ BlenderRNA *brna = ptr->data;
+ StructRNA *srna = BLI_ghash_lookup(brna->structs_map, (void *)key);
+ if (srna != NULL) {
+ RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr);
+ return true;
}
return false;
@@ -1344,6 +1370,12 @@ static void rna_def_number_property(StructRNA *srna, PropertyType type)
RNA_def_property_int_funcs(prop, "rna_Property_array_length_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Array Length", "Maximum length of the array, 0 means unlimited");
+ prop = RNA_def_property(srna, "array_dimensions", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_array(prop, RNA_MAX_ARRAY_DIMENSION);
+ RNA_def_property_int_funcs(prop, "rna_Property_array_dimensions_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Array Dimensions", "Length of each dimension of the array");
+
prop = RNA_def_property(srna, "is_array", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_NumberProperty_is_array_get", NULL);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index c63d4e775f8..cd0bcaf4cea 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -40,6 +40,7 @@
#include "IMB_imbuf_types.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -57,11 +58,6 @@
#include "RE_engine.h"
#include "RE_pipeline.h"
-#ifdef WITH_QUICKTIME
-# include "quicktime_export.h"
-# include AUD_TYPES_H
-#endif
-
#ifdef WITH_FFMPEG
# include "BKE_writeffmpeg.h"
# include <libavcodec/avcodec.h>
@@ -87,18 +83,21 @@ EnumPropertyItem rna_enum_exr_codec_items[] = {
{R_IMF_EXR_CODEC_B44, "B44", 0, "B44 (lossy)", ""},
{R_IMF_EXR_CODEC_B44A, "B44A", 0, "B44A (lossy)", ""},
{R_IMF_EXR_CODEC_DWAA, "DWAA", 0, "DWAA (lossy)", ""},
- {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""},
+ /* NOTE: Commented out for until new OpenEXR is released, see T50673. */
+ /* {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""}, */
{0, NULL, 0, NULL, NULL}
};
#endif
-EnumPropertyItem uv_sculpt_relaxation_items[] = {
+#ifndef RNA_RUNTIME
+static EnumPropertyItem uv_sculpt_relaxation_items[] = {
{UV_SCULPT_TOOL_RELAX_LAPLACIAN, "LAPLACIAN", 0, "Laplacian", "Use Laplacian method for relaxation"},
{UV_SCULPT_TOOL_RELAX_HC, "HC", 0, "HC", "Use HC method for relaxation"},
{0, NULL, 0, NULL, NULL}
};
+#endif
-EnumPropertyItem uv_sculpt_tool_items[] = {
+EnumPropertyItem rna_enum_uv_sculpt_tool_items[] = {
{UV_SCULPT_TOOL_PINCH, "PINCH", 0, "Pinch", "Pinch UVs"},
{UV_SCULPT_TOOL_RELAX, "RELAX", 0, "Relax", "Relax UVs"},
{UV_SCULPT_TOOL_GRAB, "GRAB", 0, "Grab", "Grab UVs"},
@@ -173,11 +172,13 @@ EnumPropertyItem rna_enum_snap_node_element_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem snap_uv_element_items[] = {
+#ifndef RNA_RUNTIME
+static EnumPropertyItem snap_uv_element_items[] = {
{SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments of grid"},
{SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"},
{0, NULL, 0, NULL, NULL}
};
+#endif
EnumPropertyItem rna_enum_curve_fit_method_items[] = {
{CURVE_PAINT_FIT_METHOD_REFIT, "REFIT", 0, "Refit", "Incrementally re-fit the curve (high quality)"},
@@ -263,12 +264,14 @@ EnumPropertyItem rna_enum_curve_fit_method_items[] = {
R_IMF_ENUM_TIFF \
-EnumPropertyItem image_only_type_items[] = {
+#ifdef RNA_RUNTIME
+static EnumPropertyItem image_only_type_items[] = {
IMAGE_TYPE_ITEMS_IMAGE_ONLY
{0, NULL, 0, NULL, NULL}
};
+#endif
EnumPropertyItem rna_enum_image_type_items[] = {
{0, "", 0, N_("Image"), NULL},
@@ -284,9 +287,6 @@ EnumPropertyItem rna_enum_image_type_items[] = {
#ifdef WITH_FFMPEG
{R_IMF_IMTYPE_FFMPEG, "FFMPEG", ICON_FILE_MOVIE, "FFmpeg video", "The most versatile way to output video files"},
#endif
-#ifdef WITH_QUICKTIME
- {R_IMF_IMTYPE_QUICKTIME, "QUICKTIME", ICON_FILE_MOVIE, "QuickTime", "Output video in Quicktime format"},
-#endif
{0, NULL, 0, NULL, NULL}
};
@@ -406,9 +406,36 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#ifndef RNA_RUNTIME
+static EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = {
+ /* interpolation */
+ {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"},
+ {GP_IPO_LINEAR, "LINEAR", ICON_IPO_LINEAR, "Linear", "Straight-line interpolation between A and B (i.e. no ease in/out)"},
+ {GP_IPO_CURVEMAP, "CUSTOM", ICON_IPO_BEZIER, "Custom", "Custom interpolation defined using a curve map"},
+
+ /* easing */
+ {0, "", 0, N_("Easing (by strength)"), "Predefined inertial transitions, useful for motion graphics (from least to most ''dramatic'')"},
+ {GP_IPO_SINE, "SINE", ICON_IPO_SINE, "Sinusoidal", "Sinusoidal easing (weakest, almost linear but with a slight curvature)"},
+ {GP_IPO_QUAD, "QUAD", ICON_IPO_QUAD, "Quadratic", "Quadratic easing"},
+ {GP_IPO_CUBIC, "CUBIC", ICON_IPO_CUBIC, "Cubic", "Cubic easing"},
+ {GP_IPO_QUART, "QUART", ICON_IPO_QUART, "Quartic", "Quartic easing"},
+ {GP_IPO_QUINT, "QUINT", ICON_IPO_QUINT, "Quintic", "Quintic easing"},
+ {GP_IPO_EXPO, "EXPO", ICON_IPO_EXPO, "Exponential", "Exponential easing (dramatic)"},
+ {GP_IPO_CIRC, "CIRC", ICON_IPO_CIRC, "Circular", "Circular easing (strongest and most dynamic)"},
+
+ {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"},
+ {GP_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"},
+ {GP_IPO_BOUNCE, "BOUNCE", ICON_IPO_BOUNCE, "Bounce", "Exponentially decaying parabolic bounce, like when objects collide"},
+ {GP_IPO_ELASTIC, "ELASTIC", ICON_IPO_ELASTIC, "Elastic", "Exponentially decaying sine wave, like an elastic band"},
+
+ {0, NULL, 0, NULL, NULL}
+};
+#endif
+
#ifdef RNA_RUNTIME
#include "DNA_anim_types.h"
+#include "DNA_color_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
@@ -419,8 +446,10 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#include "MEM_guardedalloc.h"
#include "BKE_brush.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -446,6 +475,29 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#include "FRS_freestyle.h"
#endif
+/* Grease Pencil Interpolation settings */
+static char *rna_GPencilInterpolateSettings_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.gpencil_interpolate");
+}
+
+static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value)
+{
+ GP_Interpolate_Settings *settings = (GP_Interpolate_Settings *)ptr->data;
+
+ /* NOTE: This cast should be fine, as we have a small + finite set of values (eGP_Interpolate_Type)
+ * that should fit well within a char
+ */
+ settings->type = (char)value;
+
+ /* init custom interpolation curve here now the first time it's used */
+ if ((settings->type == GP_IPO_CURVEMAP) &&
+ (settings->custom_ipo == NULL))
+ {
+ settings->custom_ipo = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ }
+}
+
/* Grease pencil Drawing Brushes */
static bGPDbrush *rna_GPencil_brush_new(ToolSettings *ts, const char *name, int setactive)
{
@@ -742,6 +794,21 @@ static void rna_Scene_frame_current_set(PointerRNA *ptr, int value)
data->r.cfra = value;
}
+static float rna_Scene_frame_float_get(PointerRNA *ptr)
+{
+ Scene *data = (Scene *)ptr->data;
+ return (float)data->r.cfra + data->r.subframe;
+}
+
+static void rna_Scene_frame_float_set(PointerRNA *ptr, float value)
+{
+ Scene *data = (Scene *)ptr->data;
+ /* if negative frames aren't allowed, then we can't use them */
+ FRAMENUMBER_MIN_CLAMP(value);
+ data->r.cfra = (int)value;
+ data->r.subframe = value - data->r.cfra;
+}
+
static float rna_Scene_frame_current_final_get(PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->data;
@@ -822,6 +889,12 @@ static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value)
data->r.pefra = value;
}
+static void rna_Scene_show_subframe_update(Main *UNUSED(bmain), Scene *UNUSED(current_scene), PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+ scene->r.subframe = 0.0f;
+}
+
static void rna_Scene_frame_update(Main *bmain, Scene *UNUSED(current_scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
@@ -1045,9 +1118,6 @@ static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value)
#ifdef WITH_FFMPEG
BKE_ffmpeg_image_type_verify(rd, imf);
#endif
-#ifdef WITH_QUICKTIME
- quicktime_verify_image_type(rd, imf);
-#endif
(void)rd;
}
}
@@ -1236,84 +1306,6 @@ static void rna_SceneRender_file_ext_get(PointerRNA *ptr, char *str)
BKE_image_path_ensure_ext_from_imformat(str, &rd->im_format);
}
-#ifdef WITH_QUICKTIME
-static int rna_RenderSettings_qtcodecsettings_codecType_get(PointerRNA *ptr)
-{
- QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data;
-
- return quicktime_rnatmpvalue_from_videocodectype(settings->codecType);
-}
-
-static void rna_RenderSettings_qtcodecsettings_codecType_set(PointerRNA *ptr, int value)
-{
- QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data;
-
- settings->codecType = quicktime_videocodecType_from_rnatmpvalue(value);
-}
-
-static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_codecType_itemf(
- bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem *item = NULL;
- EnumPropertyItem tmp = {0, "", 0, "", ""};
- QuicktimeCodecTypeDesc *codecTypeDesc;
- int i = 1, totitem = 0;
-
- for (i = 0; i < quicktime_get_num_videocodecs(); i++) {
- codecTypeDesc = quicktime_get_videocodecType_desc(i);
- if (!codecTypeDesc) break;
-
- tmp.value = codecTypeDesc->rnatmpvalue;
- tmp.identifier = codecTypeDesc->codecName;
- tmp.name = codecTypeDesc->codecName;
- RNA_enum_item_add(&item, &totitem, &tmp);
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
-static int rna_RenderSettings_qtcodecsettings_audiocodecType_get(PointerRNA *ptr)
-{
- QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data;
-
- return quicktime_rnatmpvalue_from_audiocodectype(settings->audiocodecType);
-}
-
-static void rna_RenderSettings_qtcodecsettings_audiocodecType_set(PointerRNA *ptr, int value)
-{
- QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data;
-
- settings->audiocodecType = quicktime_audiocodecType_from_rnatmpvalue(value);
-}
-
-static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_audiocodecType_itemf(
- bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem *item = NULL;
- EnumPropertyItem tmp = {0, "", 0, "", ""};
- QuicktimeCodecTypeDesc *codecTypeDesc;
- int i = 1, totitem = 0;
-
- for (i = 0; i < quicktime_get_num_audiocodecs(); i++) {
- codecTypeDesc = quicktime_get_audiocodecType_desc(i);
- if (!codecTypeDesc) break;
-
- tmp.value = codecTypeDesc->rnatmpvalue;
- tmp.identifier = codecTypeDesc->codecName;
- tmp.name = codecTypeDesc->codecName;
- RNA_enum_item_add(&item, &totitem, &tmp);
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-#endif
-
#ifdef WITH_FFMPEG
static void rna_FFmpegSettings_lossless_output_set(PointerRNA *ptr, int value)
{
@@ -1537,6 +1529,18 @@ static void rna_Scene_use_view_map_cache_update(Main *UNUSED(bmain), Scene *UNUS
#endif
}
+static IDProperty *rna_SceneRenderLayer_idprops(PointerRNA *ptr, bool create)
+{
+ SceneRenderLayer *srl = (SceneRenderLayer *)ptr->data;
+
+ if (create && !srl->prop) {
+ IDPropertyTemplate val = {0};
+ srl->prop = IDP_New(IDP_GROUP, &val, "SceneRenderLayer ID properties");
+ }
+
+ return srl->prop;
+}
+
static void rna_SceneRenderLayer_name_set(PointerRNA *ptr, const char *value)
{
Scene *scene = (Scene *)ptr->id.data;
@@ -1641,11 +1645,18 @@ static void rna_SceneRenderLayer_pass_update(Main *bmain, Scene *activescene, Po
Scene *scene = (Scene *)ptr->id.data;
if (scene->nodetree)
- ntreeCompositForceHidden(scene->nodetree);
-
+ ntreeCompositUpdateRLayers(scene->nodetree);
+
rna_Scene_glsl_update(bmain, activescene, ptr);
}
+static void rna_SceneRenderLayer_update_render_passes(ID *id)
+{
+ Scene *scene = (Scene *)id;
+ if (scene->nodetree)
+ ntreeCompositUpdateRLayers(scene->nodetree);
+}
+
static void rna_Scene_use_nodes_update(bContext *C, PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->data;
@@ -1724,7 +1735,7 @@ static void object_simplify_update(Object *ob)
}
}
-static void rna_Scene_use_simplify_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Scene_use_simplify_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Scene *sce = ptr->id.data;
Scene *sce_iter;
@@ -1735,6 +1746,7 @@ static void rna_Scene_use_simplify_update(Main *bmain, Scene *UNUSED(scene), Poi
object_simplify_update(base->object);
WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
+ DAG_id_tag_update(&scene->id, 0);
}
static void rna_Scene_simplify_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -1745,6 +1757,13 @@ static void rna_Scene_simplify_update(Main *bmain, Scene *UNUSED(scene), Pointer
rna_Scene_use_simplify_update(bmain, sce, ptr);
}
+static void rna_SceneRenderData_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Scene *sce = ptr->id.data;
+
+ DAG_id_tag_update(&sce->id, 0);
+}
+
static void rna_Scene_use_persistent_data_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *sce = ptr->id.data;
@@ -2137,6 +2156,73 @@ static int rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr))
#else
+/* Grease Pencil Interpolation tool settings */
+static void rna_def_gpencil_interpolate(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "GPencilInterpolateSettings", NULL);
+ RNA_def_struct_sdna(srna, "GP_Interpolate_Settings");
+ RNA_def_struct_path_func(srna, "rna_GPencilInterpolateSettings_path");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Interpolate Settings",
+ "Settings for Grease Pencil interpolation tools");
+
+ /* flags */
+ prop = RNA_def_property(srna, "interpolate_all_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS);
+ RNA_def_property_ui_text(prop, "Interpolate All Layers", "Interpolate all layers, not only active");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "interpolate_selected_only", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED);
+ RNA_def_property_ui_text(prop, "Interpolate Selected Strokes", "Interpolate only selected strokes in the original frame");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* interpolation type */
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_interpolation_mode_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_GPencilInterpolateSettings_type_set", NULL);
+ RNA_def_property_ui_text(prop, "Type",
+ "Interpolation method to use the next time 'Interpolate Sequence' is run");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* easing */
+ prop = RNA_def_property(srna, "easing", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "easing");
+ RNA_def_property_enum_items(prop, rna_enum_beztriple_interpolation_easing_items);
+ RNA_def_property_ui_text(prop, "Easing",
+ "Which ends of the segment between the preceding and following grease pencil frames "
+ "easing interpolation is applied to");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* easing options */
+ prop = RNA_def_property(srna, "back", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "back");
+ RNA_def_property_ui_text(prop, "Back", "Amount of overshoot for 'back' easing");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "amplitude");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX); /* only positive values... */
+ RNA_def_property_ui_text(prop, "Amplitude", "Amount to boost elastic bounces for 'elastic' easing");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "period", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "period");
+ RNA_def_property_ui_text(prop, "Period", "Time between bounces for elastic easing");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* custom curvemap */
+ prop = RNA_def_property(srna, "interpolation_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "custom_ipo");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Interpolation Curve",
+ "Custom curve to control 'sequence' interpolation between Grease Pencil frames");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+}
+
/* Grease Pencil Drawing Brushes */
static void rna_def_gpencil_brush(BlenderRNA *brna)
{
@@ -2310,7 +2396,7 @@ static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_GPencil_brush_new");
RNA_def_function_ui_description(func, "Add a new grease pencil brush");
parm = RNA_def_string(func, "name", "GPencilBrush", MAX_NAME, "Name", "Name of the brush");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "set_active", 0, "Set Active", "Set the newly created brush to the active brush");
parm = RNA_def_pointer(func, "palette", "GPencilBrush", "", "The newly created brush");
RNA_def_function_return(func, parm);
@@ -2319,8 +2405,8 @@ static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a grease pencil brush");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "brush", "GPencilBrush", "", "The 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPencilBrush");
@@ -2505,7 +2591,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "uv_sculpt_tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "uv_sculpt_tool");
- RNA_def_property_enum_items(prop, uv_sculpt_tool_items);
+ RNA_def_property_enum_items(prop, rna_enum_uv_sculpt_tool_items);
RNA_def_property_ui_text(prop, "UV Sculpt Tools", "Select Tools for the UV sculpt brushes");
prop = RNA_def_property(srna, "uv_relax_method", PROP_ENUM, PROP_NONE);
@@ -2672,7 +2758,14 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt");
RNA_def_property_struct_type(prop, "GPencilSculptSettings");
- RNA_def_property_ui_text(prop, "Grease Pencil Sculpt", "");
+ RNA_def_property_ui_text(prop, "Grease Pencil Sculpt",
+ "Settings for stroke sculpting tools and brushes");
+
+ prop = RNA_def_property(srna, "gpencil_interpolate", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "gp_interpolate");
+ RNA_def_property_struct_type(prop, "GPencilInterpolateSettings");
+ RNA_def_property_ui_text(prop, "Grease Pencil Interpolate",
+ "Settings for Grease Pencil Interpolation tools");
/* Grease Pencil - Drawing brushes */
prop = RNA_def_property(srna, "gpencil_brushes", PROP_COLLECTION, PROP_NONE);
@@ -3609,8 +3702,8 @@ static void rna_def_freestyle_modules(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a style module from scene render layer Freestyle settings");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "module", "FreestyleModuleSettings", "", "Style module 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
@@ -3642,7 +3735,7 @@ static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a line set to scene render layer Freestyle settings");
RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_SELF_ID);
parm = RNA_def_string(func, "name", "LineSet", 0, "", "New name for the line set (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "lineset", "FreestyleLineSet", "", "Newly created line set");
RNA_def_function_return(func, parm);
@@ -3650,8 +3743,8 @@ static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a line set from scene render layer Freestyle settings");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "lineset", "FreestyleLineSet", "", "Line set 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_freestyle_settings(BlenderRNA *brna)
@@ -4927,14 +5020,20 @@ static void rna_def_scene_render_layer(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+ FunctionRNA *func;
srna = RNA_def_struct(brna, "SceneRenderLayer", NULL);
RNA_def_struct_ui_text(srna, "Scene Render Layer", "Render layer");
RNA_def_struct_ui_icon(srna, ICON_RENDERLAYERS);
RNA_def_struct_path_func(srna, "rna_SceneRenderLayer_path");
+ RNA_def_struct_idprops_func(srna, "rna_SceneRenderLayer_idprops");
rna_def_render_layer_common(srna, 1);
+ func = RNA_def_function(srna, "update_render_passes", "rna_SceneRenderLayer_update_render_passes");
+ RNA_def_function_ui_description(func, "Requery the enabled render passes from the render engine");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF);
+
/* Freestyle */
rna_def_freestyle_settings(brna);
@@ -4979,7 +5078,7 @@ static void rna_def_render_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a render layer to scene");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_string(func, "name", "RenderLayer", 0, "", "New name for the render layer (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "result", "SceneRenderLayer", "", "Newly created render layer");
RNA_def_function_return(func, parm);
@@ -4987,8 +5086,8 @@ static void rna_def_render_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a render layer");
RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "layer", "SceneRenderLayer", "", "Render layer 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
/* Render Views - MultiView */
@@ -5058,7 +5157,7 @@ static void rna_def_render_views(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a render view to scene");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_string(func, "name", "RenderView", 0, "", "New name for the marker (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "result", "SceneRenderView", "", "Newly created render view");
RNA_def_function_return(func, parm);
@@ -5066,8 +5165,8 @@ static void rna_def_render_views(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a render view");
RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "view", "SceneRenderView", "", "Render view 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_image_format_stereo3d_format(BlenderRNA *brna)
@@ -5245,7 +5344,7 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "jpeg2k_codec", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "jp2_codec");
RNA_def_property_enum_items(prop, jp2_codec_items);
- RNA_def_property_ui_text(prop, "Codec", "Codec settings for Jpek2000");
+ RNA_def_property_ui_text(prop, "Codec", "Codec settings for Jpeg2000");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
#endif
@@ -5550,106 +5649,6 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Audio Channels", "Audio channel count");
}
-#ifdef WITH_QUICKTIME
-static void rna_def_scene_quicktime_settings(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static EnumPropertyItem quicktime_codec_type_items[] = {
- {0, "codec", 0, "codec", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static EnumPropertyItem quicktime_audio_samplerate_items[] = {
- {22050, "22050", 0, "22kHz", ""},
- {44100, "44100", 0, "44.1kHz", ""},
- {48000, "48000", 0, "48kHz", ""},
- {88200, "88200", 0, "88.2kHz", ""},
- {96000, "96000", 0, "96kHz", ""},
- {192000, "192000", 0, "192kHz", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static EnumPropertyItem quicktime_audio_bitdepth_items[] = {
- {AUD_FORMAT_U8, "8BIT", 0, "8bit", ""},
- {AUD_FORMAT_S16, "16BIT", 0, "16bit", ""},
- {AUD_FORMAT_S24, "24BIT", 0, "24bit", ""},
- {AUD_FORMAT_S32, "32BIT", 0, "32bit", ""},
- {AUD_FORMAT_FLOAT32, "FLOAT32", 0, "float32", ""},
- {AUD_FORMAT_FLOAT64, "FLOAT64", 0, "float64", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static EnumPropertyItem quicktime_audio_bitrate_items[] = {
- {64000, "64000", 0, "64kbps", ""},
- {112000, "112000", 0, "112kpbs", ""},
- {128000, "128000", 0, "128kbps", ""},
- {192000, "192000", 0, "192kbps", ""},
- {256000, "256000", 0, "256kbps", ""},
- {320000, "320000", 0, "320kbps", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* QuickTime */
- srna = RNA_def_struct(brna, "QuickTimeSettings", NULL);
- RNA_def_struct_sdna(srna, "QuicktimeCodecSettings");
- RNA_def_struct_ui_text(srna, "QuickTime Settings", "QuickTime related settings for the scene");
-
- prop = RNA_def_property(srna, "codec_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "codecType");
- RNA_def_property_enum_items(prop, quicktime_codec_type_items);
- RNA_def_property_enum_funcs(prop, "rna_RenderSettings_qtcodecsettings_codecType_get",
- "rna_RenderSettings_qtcodecsettings_codecType_set",
- "rna_RenderSettings_qtcodecsettings_codecType_itemf");
- RNA_def_property_ui_text(prop, "Codec", "QuickTime codec type");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "codec_spatial_quality", PROP_INT, PROP_PERCENTAGE);
- RNA_def_property_int_sdna(prop, NULL, "codecSpatialQuality");
- RNA_def_property_range(prop, 0, 100);
- RNA_def_property_ui_text(prop, "Spatial quality", "Intra-frame spatial quality level");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "audiocodec_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "audiocodecType");
- RNA_def_property_enum_items(prop, quicktime_codec_type_items);
- RNA_def_property_enum_funcs(prop, "rna_RenderSettings_qtcodecsettings_audiocodecType_get",
- "rna_RenderSettings_qtcodecsettings_audiocodecType_set",
- "rna_RenderSettings_qtcodecsettings_audiocodecType_itemf");
- RNA_def_property_ui_text(prop, "Audio Codec", "QuickTime audio codec type");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "audio_samplerate", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "audioSampleRate");
- RNA_def_property_enum_items(prop, quicktime_audio_samplerate_items);
- RNA_def_property_ui_text(prop, "Smp Rate", "Sample Rate");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "audio_bitdepth", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "audioBitDepth");
- RNA_def_property_enum_items(prop, quicktime_audio_bitdepth_items);
- RNA_def_property_ui_text(prop, "Bit Depth", "Bit Depth");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "audio_resampling_hq", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "audioCodecFlags", QTAUDIO_FLAG_RESAMPLE_NOHQ);
- RNA_def_property_ui_text(prop, "HQ", "Use High Quality resampling algorithm");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "audio_codec_isvbr", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "audioCodecFlags", QTAUDIO_FLAG_CODEC_ISCBR);
- RNA_def_property_ui_text(prop, "VBR", "Use Variable Bit Rate compression (improves quality at same bitrate)");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "audio_bitrate", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "audioBitRate");
- RNA_def_property_enum_items(prop, quicktime_audio_bitrate_items);
- RNA_def_property_ui_text(prop, "Bitrate", "Compressed audio bitrate");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-}
-#endif
-
static void rna_def_scene_render_data(BlenderRNA *brna)
{
StructRNA *srna;
@@ -5714,6 +5713,15 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem pixel_size_items[] = {
+ {0, "AUTO", 0, "Automatic", "Automatic pixel size, depends on the UI scale"},
+ {1, "1", 0, "1x", "Render at full resolution"},
+ {2, "2", 0, "2x", "Render at 50% resolution"},
+ {4, "4", 0, "4x", "Render at 25% resolution"},
+ {8, "8", 0, "8x", "Render at 12.5% resolution"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
static EnumPropertyItem octree_resolution_items[] = {
{64, "64", 0, "64", ""},
{128, "128", 0, "128", ""},
@@ -5774,9 +5782,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
rna_def_scene_ffmpeg_settings(brna);
-#ifdef WITH_QUICKTIME
- rna_def_scene_quicktime_settings(brna);
-#endif
srna = RNA_def_struct(brna, "RenderSettings", NULL);
RNA_def_struct_sdna(srna, "RenderData");
@@ -5837,6 +5842,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"progressively increasing it to the full viewport size");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "preview_pixel_size", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "preview_pixel_size");
+ RNA_def_property_enum_items(prop, pixel_size_items);
+ RNA_def_property_ui_text(prop, "Pixel Size", "Pixel size for viewport rendering");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderData_update");
+
prop = RNA_def_property(srna, "pixel_aspect_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xasp");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
@@ -5855,14 +5866,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"Vertical aspect ratio - for anamorphic or non-square pixel output");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneCamera_update");
-#ifdef WITH_QUICKTIME
- prop = RNA_def_property(srna, "quicktime", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "QuickTimeSettings");
- RNA_def_property_pointer_sdna(prop, NULL, "qtcodecsettings");
- RNA_def_property_flag(prop, PROP_NEVER_UNLINK);
- RNA_def_property_ui_text(prop, "QuickTime Settings", "QuickTime related settings for the scene");
-#endif
-
prop = RNA_def_property(srna, "ffmpeg", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "FFmpegSettings");
RNA_def_property_pointer_sdna(prop, NULL, "ffcodecdata");
@@ -6069,8 +6072,8 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "blurfac");
RNA_def_property_ui_range(prop, 0.01f, 2.0f, 1, 2);
- RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close "
+ "(NOTE: Blender Internal does not support animated shutter)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "motion_blur_shutter_curve", PROP_POINTER, PROP_NONE);
@@ -6432,11 +6435,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
/* sequencer draw options */
- prop = RNA_def_property(srna, "use_sequencer_gl_preview", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_GL_PREV);
- RNA_def_property_ui_text(prop, "Sequencer OpenGL", "");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update");
-
#if 0 /* see R_SEQ_GL_REND comment */
prop = RNA_def_property(srna, "use_sequencer_gl_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_GL_REND);
@@ -6449,10 +6447,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sequencer Preview Shading", "Method to draw in the sequencer view");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update");
+#if 0 /* UNUSED, see R_SEQ_GL_REND comment */
prop = RNA_def_property(srna, "sequencer_gl_render", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "seq_rend_type");
RNA_def_property_enum_items(prop, rna_enum_viewport_shade_items);
+ /* XXX Label and tooltips are obviously wrong! */
RNA_def_property_ui_text(prop, "Sequencer Preview Shading", "Method to draw in the sequencer view");
+#endif
prop = RNA_def_property(srna, "use_sequencer_gl_textured_solid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_SOLID_TEX);
@@ -6597,14 +6598,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "BakeSettings");
RNA_def_property_ui_text(prop, "Bake Data", "");
- /* Debugging settings. */
-#ifdef WITH_CYCLES_DEBUG
- prop = RNA_def_property(srna, "debug_pass_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_enum_render_pass_debug_type_items);
- RNA_def_property_ui_text(prop, "Debug Pass Type", "Type of the debug pass to use");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-#endif
-
/* Nestled Data */
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
@@ -6635,7 +6628,7 @@ static void rna_def_scene_objects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Link object to scene, run scene.update() after");
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "object", "Object", "", "Object to add to scene");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "base", "ObjectBase", "", "The newly created base");
RNA_def_function_return(func, parm);
@@ -6643,7 +6636,7 @@ static void rna_def_scene_objects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Unlink object from scene");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove from scene");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Object");
@@ -6694,7 +6687,7 @@ static void rna_def_timeline_markers(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_TimeLine_add");
RNA_def_function_ui_description(func, "Add a keyframe to the curve");
parm = RNA_def_string(func, "name", "Marker", 0, "", "New name for the marker (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame", 1, -MAXFRAME, MAXFRAME, "", "The frame for the new marker", -MAXFRAME, MAXFRAME);
parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Newly created timeline marker");
RNA_def_function_return(func, parm);
@@ -6704,8 +6697,8 @@ static void rna_def_timeline_markers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a timeline marker");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Timeline marker 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "clear", "rna_TimeLine_clear");
RNA_def_function_ui_description(func, "Remove all timeline markers");
@@ -6732,7 +6725,6 @@ static void rna_def_scene_keying_sets(BlenderRNA *brna, PropertyRNA *cprop)
/* name */
RNA_def_string(func, "idname", "KeyingSet", 64, "IDName", "Internal identifier of Keying Set");
RNA_def_string(func, "name", "KeyingSet", 64, "Name", "User visible name of Keying Set");
-
/* returns the new KeyingSet */
parm = RNA_def_pointer(func, "keyingset", "KeyingSet", "", "Newly created Keying Set");
RNA_def_function_return(func, parm);
@@ -6824,7 +6816,7 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
RNA_def_property_array(prop, 2);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_array_default(prop, default_title);
- RNA_def_property_ui_text(prop, "Title Safe margins", "Safe area for text and graphics");
+ RNA_def_property_ui_text(prop, "Title Safe Margins", "Safe area for text and graphics");
RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "action", PROP_FLOAT, PROP_XYZ);
@@ -6835,7 +6827,6 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Action Safe Margins", "Safe area for general elements");
RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
-
prop = RNA_def_property(srna, "title_center", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "title_center");
RNA_def_property_array(prop, 2);
@@ -6958,8 +6949,19 @@ void RNA_def_scene(BlenderRNA *brna)
prop = RNA_def_property(srna, "frame_subframe", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "r.subframe");
RNA_def_property_ui_text(prop, "Current Sub-Frame", "");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
-
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 2);
+ RNA_def_property_update(prop, NC_SCENE | ND_FRAME, "rna_Scene_frame_update");
+
+ prop = RNA_def_property(srna, "frame_float", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_ui_text(prop, "Current Sub-Frame", "");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
+ RNA_def_property_ui_range(prop, MINAFRAME, MAXFRAME, 0.1, 2);
+ RNA_def_property_float_funcs(prop, "rna_Scene_frame_float_get", "rna_Scene_frame_float_set", NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_FRAME, "rna_Scene_frame_update");
+
prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_int_sdna(prop, NULL, "r.sfra");
@@ -7024,7 +7026,15 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_int_funcs(prop, NULL, "rna_Scene_preview_range_end_frame_set", NULL);
RNA_def_property_ui_text(prop, "Preview Range End Frame", "Alternative end frame for UI playback");
RNA_def_property_update(prop, NC_SCENE | ND_FRAME, NULL);
-
+
+ /* Subframe for moblur debug. */
+ prop = RNA_def_property(srna, "show_subframe", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "r.flag", SCER_SHOW_SUBFRAME);
+ RNA_def_property_ui_text(prop, "Show Subframe",
+ "Show current scene subframe and allow set it using interface tools");
+ RNA_def_property_update(prop, NC_SCENE | ND_FRAME, "rna_Scene_show_subframe_update");
+
/* Timeline / Time Navigation settings */
prop = RNA_def_property(srna, "show_keys_from_selected_only", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SCE_KEYS_NO_SELONLY);
@@ -7216,8 +7226,8 @@ void RNA_def_scene(BlenderRNA *brna)
/* Statistics */
func = RNA_def_function(srna, "statistics", "ED_info_stats_string");
- prop = RNA_def_string(func, "statistics", NULL, 0, "Statistics", "");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_string(func, "statistics", NULL, 0, "Statistics", "");
+ RNA_def_function_return(func, parm);
/* Grease Pencil */
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
@@ -7267,6 +7277,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_define_animate_sdna(false);
rna_def_tool_settings(brna);
rna_def_gpencil_brush(brna);
+ rna_def_gpencil_interpolate(brna);
rna_def_unified_paint_settings(brna);
rna_def_curve_paint_settings(brna);
rna_def_statvis(brna);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 85c0b01334f..16d91a4964b 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -164,7 +164,6 @@ static void rna_Scene_ray_cast(
bool ret = ED_transform_snap_object_project_ray_ex(
sctx,
- SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
},
@@ -208,6 +207,8 @@ static void rna_Scene_alembic_export(
int renderable_only,
int face_sets,
int use_subdiv_schema,
+ int export_hair,
+ int export_particles,
int compression_type,
int packuv,
float scale,
@@ -225,8 +226,8 @@ static void rna_Scene_alembic_export(
.frame_start = frame_start,
.frame_end = frame_end,
- .frame_step_xform = 1.0 / (double)xform_samples,
- .frame_step_shape = 1.0 / (double)geom_samples,
+ .frame_samples_xform = xform_samples,
+ .frame_samples_shape = geom_samples,
.shutter_open = shutter_open,
.shutter_close = shutter_close,
@@ -241,16 +242,18 @@ static void rna_Scene_alembic_export(
.renderable_only = renderable_only,
.face_sets = face_sets,
.use_subdiv_schema = use_subdiv_schema,
+ .export_hair = export_hair,
+ .export_particles = export_particles,
.compression_type = compression_type,
.packuv = packuv,
- .triangulate = triangulate,
- .quad_method = quad_method,
- .ngon_method = ngon_method,
+ .triangulate = triangulate,
+ .quad_method = quad_method,
+ .ngon_method = ngon_method,
.global_scale = scale,
};
- ABC_export(scene, C, filepath, &params);
+ ABC_export(scene, C, filepath, &params, true);
#ifdef WITH_PYTHON
BPy_END_ALLOW_THREADS;
@@ -263,34 +266,55 @@ static void rna_Scene_alembic_export(
/* don't remove this, as COLLADA exporting cannot be done through operators in render() callback. */
#include "../../collada/collada.h"
+/* Note: This definition must match to the generated function call */
static void rna_Scene_collada_export(
Scene *scene,
- const char *filepath,
+ const char *filepath,
int apply_modifiers,
- int export_mesh_type,
+ int export_mesh_type,
int selected,
int include_children,
int include_armatures,
int include_shapekeys,
int deform_bones_only,
-
int active_uv_only,
- int include_uv_textures,
- int include_material_textures,
+ int export_texture_type,
int use_texture_copies,
-
- int use_ngons,
+ int triangulate,
int use_object_instantiation,
int use_blender_profile,
int sort_by_name,
+ int export_transformation_type,
int open_sim,
- int export_transformation_type)
+ int limit_precision,
+ int keep_bind_info)
{
- collada_export(scene, filepath, apply_modifiers, export_mesh_type, selected,
- include_children, include_armatures, include_shapekeys, deform_bones_only,
- active_uv_only, include_uv_textures, include_material_textures,
- use_texture_copies, use_ngons, use_object_instantiation, use_blender_profile, sort_by_name, export_transformation_type, open_sim);
+ collada_export(scene,
+ filepath,
+
+ apply_modifiers,
+ export_mesh_type,
+
+ selected,
+ include_children,
+ include_armatures,
+ include_shapekeys,
+ deform_bones_only,
+
+ active_uv_only,
+ export_texture_type,
+ use_texture_copies,
+
+ triangulate,
+ use_object_instantiation,
+ use_blender_profile,
+ sort_by_name,
+
+ export_transformation_type,
+ open_sim,
+ limit_precision,
+ keep_bind_info);
}
#endif
@@ -305,7 +329,7 @@ void RNA_api_scene(StructRNA *srna)
func = RNA_def_function(srna, "frame_set", "rna_Scene_frame_set");
RNA_def_function_ui_description(func, "Set scene frame updating all objects immediately");
parm = RNA_def_int(func, "frame", 0, MINAFRAME, MAXFRAME, "", "Frame number to set", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_float(func, "subframe", 0.0, 0.0, 1.0, "", "Sub-frame time, between 0.0 and 1.0", 0.0, 1.0);
func = RNA_def_function(srna, "update", "rna_Scene_update_tagged");
@@ -315,34 +339,31 @@ void RNA_api_scene(StructRNA *srna)
func = RNA_def_function(srna, "uvedit_aspect", "rna_Scene_uvedit_aspect");
RNA_def_function_ui_description(func, "Get uv aspect for current object");
parm = RNA_def_pointer(func, "object", "Object", "", "Object");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
-
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_float_vector(func, "result", 2, NULL, 0.0f, FLT_MAX, "", "aspect", 0.0f, FLT_MAX);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
/* Ray Cast */
func = RNA_def_function(srna, "ray_cast", "rna_Scene_ray_cast");
RNA_def_function_ui_description(func, "Cast a ray onto in object space");
-
/* ray start and end */
parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_float(func, "distance", BVH_RAYCAST_DIST_MAX, 0.0, BVH_RAYCAST_DIST_MAX,
"", "Maximum distance", 0.0, BVH_RAYCAST_DIST_MAX);
-
/* return location and normal */
parm = RNA_def_boolean(func, "result", 0, "", "");
RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
"The hit location of this ray cast", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal",
"The face normal at the ray cast hit location", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0);
RNA_def_function_output(func, parm);
@@ -355,40 +376,69 @@ void RNA_api_scene(StructRNA *srna)
/* don't remove this, as COLLADA exporting cannot be done through operators in render() callback. */
func = RNA_def_function(srna, "collada_export", "rna_Scene_collada_export");
parm = RNA_def_string(func, "filepath", NULL, FILE_MAX, "File Path", "File path to write Collada file");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */
- parm = RNA_def_boolean(func, "apply_modifiers", 0, "Apply Modifiers", "Apply modifiers");
- parm = RNA_def_int(func, "export_mesh_type", 0, INT_MIN, INT_MAX,
+
+ RNA_def_boolean(func, "apply_modifiers", false,
+ "Apply Modifiers", "Apply modifiers to exported mesh (non destructive))");
+
+ RNA_def_int(func, "export_mesh_type", 0, INT_MIN, INT_MAX,
"Resolution", "Modifier resolution for export", INT_MIN, INT_MAX);
- parm = RNA_def_boolean(func, "selected", 0, "Selection Only", "Export only selected elements");
- parm = RNA_def_boolean(func, "include_children", 0, "Include Children", "Export all children of selected objects (even if not selected)");
- parm = RNA_def_boolean(func, "include_armatures", 0, "Include Armatures", "Export related armatures (even if not selected)");
- parm = RNA_def_boolean(func, "include_shapekeys", 0, "Include Shape Keys", "Export all Shape Keys from Mesh Objects");
- parm = RNA_def_boolean(func, "deform_bones_only", 0, "Deform Bones only", "Only export deforming bones with armatures");
-
- parm = RNA_def_boolean(func, "active_uv_only", 0, "Active UV Layer only", "Export only the active UV Layer");
- parm = RNA_def_boolean(func, "include_uv_textures", 0, "Include UV Textures", "Export textures assigned to the object UV maps");
- parm = RNA_def_boolean(func, "include_material_textures", 0, "Include Material Textures", "Export textures assigned to the object Materials");
- parm = RNA_def_boolean(func, "use_texture_copies", 0, "copy", "Copy textures to same folder where the .dae file is exported");
-
- parm = RNA_def_boolean(func, "use_ngons", 1, "Use NGons", "Keep NGons in Export");
- parm = RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances", "Instantiate multiple Objects from same Data");
- parm = RNA_def_boolean(func, "use_blender_profile", 1, "Use Blender Profile", "Export additional Blender specific information (for material, shaders, bones, etc.)");
- parm = RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name");
- parm = RNA_def_boolean(func, "open_sim", 0, "Export for SL/OpenSim", "Compatibility mode for SL, OpenSim and similar online worlds");
-
- parm = RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX,
- "Transformation", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
-
- RNA_def_function_ui_description(func, "Export to collada file");
+
+ RNA_def_boolean(func, "selected", false, "Selection Only", "Export only selected elements");
+
+ RNA_def_boolean(func, "include_children", false,
+ "Include Children", "Export all children of selected objects (even if not selected)");
+
+ RNA_def_boolean(func, "include_armatures", false,
+ "Include Armatures", "Export related armatures (even if not selected)");
+
+ RNA_def_boolean(func, "include_shapekeys", true, "Include Shape Keys", "Export all Shape Keys from Mesh Objects");
+
+ RNA_def_boolean(func, "deform_bones_only", false,
+ "Deform Bones only", "Only export deforming bones with armatures");
+
+ RNA_def_boolean(func, "active_uv_only", false, "Only Selected UV Map", "Export only the selected UV Map");
+
+ RNA_def_int(func, "export_texture_type", 0, INT_MIN, INT_MAX,
+ "Texture Type", "Type for exported Textures (UV or MAT)", INT_MIN, INT_MAX);
+
+ RNA_def_boolean(func, "use_texture_copies", true,
+ "Copy", "Copy textures to same folder where the .dae file is exported");
+
+ RNA_def_boolean(func, "triangulate", true, "Triangulate", "Export Polygons (Quads & NGons) as Triangles");
+
+ RNA_def_boolean(func, "use_object_instantiation", true,
+ "Use Object Instances", "Instantiate multiple Objects from same Data");
+
+ RNA_def_boolean(func, "use_blender_profile", true, "Use Blender Profile",
+ "Export additional Blender specific information (for material, shaders, bones, etc.)");
+
+ RNA_def_boolean(func, "sort_by_name", false, "Sort by Object name", "Sort exported data by Object name");
+
+ RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX,
+ "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
+
+ RNA_def_boolean(func, "open_sim", false,
+ "Export to SL/OpenSim", "Compatibility mode for SL, OpenSim and other compatible online worlds");
+
+ RNA_def_boolean(func, "limit_precision", false,
+ "Limit Precision",
+ "Reduce the precision of the exported data to 6 digits");
+
+ RNA_def_boolean(func, "keep_bind_info", false,
+ "Keep Bind Info",
+ "Store bind pose information in custom bone properties for later use during Collada export");
+
#endif
#ifdef WITH_ALEMBIC
+ /* XXX Deprecated, will be removed in 2.8 in favour of calling the export operator. */
func = RNA_def_function(srna, "alembic_export", "rna_Scene_alembic_export");
- RNA_def_function_ui_description(func, "Export to Alembic file");
+ RNA_def_function_ui_description(func, "Export to Alembic file (deprecated, use the Alembic export operator)");
parm = RNA_def_string(func, "filepath", NULL, FILE_MAX, "File Path", "File path to write Alembic file");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */
RNA_def_int(func, "frame_start", 1, INT_MIN, INT_MAX, "Start", "Start Frame", INT_MIN, INT_MAX);
@@ -407,6 +457,8 @@ void RNA_api_scene(StructRNA *srna)
RNA_def_boolean(func, "renderable_only" , 0, "Renderable objects only", "Export only objects marked renderable in the outliner");
RNA_def_boolean(func, "face_sets" , 0, "Facesets", "Export face sets");
RNA_def_boolean(func, "subdiv_schema", 0, "Use Alembic subdivision Schema", "Use Alembic subdivision Schema");
+ RNA_def_boolean(func, "export_hair", 1, "Export Hair", "Exports hair particle systems as animated curves");
+ RNA_def_boolean(func, "export_particles", 1, "Export Particles", "Exports non-hair particle systems");
RNA_def_enum(func, "compression_type", rna_enum_abc_compression_items, 0, "Compression", "");
RNA_def_boolean(func, "packuv" , 0, "Export with packed UV islands", "Export with packed UV islands");
RNA_def_float(func, "scale", 1.0f, 0.0001f, 1000.0f, "Scale", "Value by which to enlarge or shrink the objects with respect to the world's origin", 0.0001f, 1000.0f);
@@ -428,13 +480,12 @@ void RNA_api_scene_render(StructRNA *srna)
RNA_def_function_ui_description(func, "Return the absolute path to the filename to be written for a given frame");
RNA_def_int(func, "frame", INT_MIN, INT_MIN, INT_MAX, "",
"Frame number to use, if unset the current frame will be used", MINAFRAME, MAXFRAME);
- parm = RNA_def_boolean(func, "preview", 0, "Preview", "Use preview range");
- parm = RNA_def_string_file_path(func, "view", NULL, FILE_MAX, "View",
+ RNA_def_boolean(func, "preview", 0, "Preview", "Use preview range");
+ RNA_def_string_file_path(func, "view", NULL, FILE_MAX, "View",
"The name of the view to use to replace the \"%\" chars");
-
parm = RNA_def_string_file_path(func, "filepath", NULL, FILE_MAX, "File Path",
"The resulting filepath from the scenes render settings");
- RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 43d5cda17ae..b44e404c364 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -285,22 +285,22 @@ static void rna_def_view2d_api(StructRNA *srna)
func = RNA_def_function(srna, "region_to_view", "rna_View2D_region_to_view");
RNA_def_function_ui_description(func, "Transform region coordinates to 2D view");
parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "x", "Region x coordinate", -10000, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "y", "Region y coordinate", -10000, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float_array(func, "result", 2, view_default, -FLT_MAX, FLT_MAX, "Result", "View coordinates", -10000.0f, 10000.0f);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
func = RNA_def_function(srna, "view_to_region", "rna_View2D_view_to_region");
RNA_def_function_ui_description(func, "Transform 2D view coordinates to region");
parm = RNA_def_float(func, "x", 0.0f, -FLT_MAX, FLT_MAX, "x", "2D View x coordinate", -10000.0f, 10000.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func, "y", 0.0f, -FLT_MAX, FLT_MAX, "y", "2D View y coordinate", -10000.0f, 10000.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "clip", 1, "Clip", "Clip coordinates to the visible region");
parm = RNA_def_int_array(func, "result", 2, region_default, INT_MIN, INT_MAX, "Result", "Region coordinates", -10000, 10000);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 7f405f0fb1f..422be83a7f6 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "rna_internal.h"
@@ -75,13 +76,15 @@ EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = {
{ 0, NULL, 0, NULL, NULL }
};
-EnumPropertyItem rna_enum_gpencil_lockaxis_items[] = {
+#ifndef RNA_RUNTIME
+static EnumPropertyItem rna_enum_gpencil_lockaxis_items[] = {
{ GP_LOCKAXIS_NONE, "GP_LOCKAXIS_NONE", 0, "None", "" },
{ GP_LOCKAXIS_X, "GP_LOCKAXIS_X", 0, "X", "Project strokes to plane locked to X" },
{ GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", 0, "Y", "Project strokes to plane locked to Y" },
{ GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", 0, "Z", "Project strokes to plane locked to Z" },
{ 0, NULL, 0, NULL, NULL }
};
+#endif
EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
{BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""},
@@ -668,22 +671,20 @@ static void rna_def_vertex_paint(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_VertexPaint_path");
RNA_def_struct_ui_text(srna, "Vertex Paint", "Properties of vertex and weight paint mode");
- /* vertex paint only */
- prop = RNA_def_property(srna, "use_normal", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_NORMALS);
- RNA_def_property_ui_text(prop, "Normals", "Apply the vertex normal before painting");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "use_spray", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_SPRAY);
- RNA_def_property_ui_text(prop, "Spray", "Keep applying paint effect while holding mouse");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
/* weight paint only */
prop = RNA_def_property(srna, "use_group_restrict", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_ONLYVGROUP);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_FLAG_VGROUP_RESTRICT);
RNA_def_property_ui_text(prop, "Restrict", "Restrict painting to vertices in the group");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* Mirroring */
+ prop = RNA_def_property(srna, "radial_symmetry", PROP_INT, PROP_XYZ);
+ RNA_def_property_int_sdna(prop, NULL, "radial_symm");
+ RNA_def_property_int_default(prop, 1);
+ RNA_def_property_range(prop, 1, 64);
+ RNA_def_property_ui_range(prop, 1, 32, 1, 1);
+ RNA_def_property_ui_text(prop, "Radial Symmetry Count X Axis",
+ "Number of times to copy strokes across the surface");
}
static void rna_def_image_paint(BlenderRNA *brna)
@@ -1047,15 +1048,6 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Affect Thickness", "The brush affects the thickness of the point");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "interpolate_all_layers", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS);
- RNA_def_property_ui_text(prop, "Interpolate All Layers", "Interpolate all layers, not only active");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "interpolate_selected_only", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED);
- RNA_def_property_ui_text(prop, "Interpolate Selected Strokes", "Interpolate only selected strokes in the original frame");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "selection_alpha", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "alpha");
diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c
index ee24a434486..d0afab7a1e3 100644
--- a/source/blender/makesrna/intern/rna_sensor.c
+++ b/source/blender/makesrna/intern/rna_sensor.c
@@ -32,6 +32,7 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_sensor_api.c b/source/blender/makesrna/intern/rna_sensor_api.c
index 476f0589bc9..b0c4109b1df 100644
--- a/source/blender/makesrna/intern/rna_sensor_api.c
+++ b/source/blender/makesrna/intern/rna_sensor_api.c
@@ -65,13 +65,13 @@ void RNA_api_sensor(StructRNA *srna)
func = RNA_def_function(srna, "link", "rna_Sensor_link");
RNA_def_function_ui_description(func, "Link the sensor to a controller");
parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to link to");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_update(parm, NC_LOGIC, NULL);
func = RNA_def_function(srna, "unlink", "rna_Sensor_unlink");
RNA_def_function_ui_description(func, "Unlink the sensor from a controller");
parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to unlink from");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_update(parm, NC_LOGIC, NULL);
}
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index bb9c2a6c2fd..520a1c2f730 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -341,7 +341,7 @@ static void rna_Sequence_use_translation_set(PointerRNA *ptr, int value)
}
}
else {
- seq->flag ^= SEQ_USE_TRANSFORM;
+ seq->flag &= ~SEQ_USE_TRANSFORM;
}
}
@@ -355,7 +355,7 @@ static void rna_Sequence_use_crop_set(PointerRNA *ptr, int value)
}
}
else {
- seq->flag ^= SEQ_USE_CROP;
+ seq->flag &= ~SEQ_USE_CROP;
}
}
@@ -725,8 +725,9 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), Poin
static void rna_Sequence_sound_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Sequence *seq = (Sequence *) ptr->data;
-
- BKE_sound_update_scene_sound(seq->scene_sound, seq->sound);
+ if (seq->sound != NULL) {
+ BKE_sound_update_scene_sound(seq->scene_sound, seq->sound);
+ }
rna_Sequence_update(bmain, scene, ptr);
}
@@ -1095,7 +1096,7 @@ static void rna_def_strip_element(BlenderRNA *brna)
prop = RNA_def_property(srna, "filename", PROP_STRING, PROP_FILENAME);
RNA_def_property_string_sdna(prop, NULL, "name");
- RNA_def_property_ui_text(prop, "Filename", "");
+ RNA_def_property_ui_text(prop, "Filename", "Name of the source file");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceElement_update");
prop = RNA_def_property(srna, "orig_width", PROP_INT, PROP_NONE);
@@ -1120,25 +1121,25 @@ static void rna_def_strip_crop(BlenderRNA *brna)
prop = RNA_def_property(srna, "max_y", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "top");
- RNA_def_property_ui_text(prop, "Top", "");
+ RNA_def_property_ui_text(prop, "Top", "Number of pixels to crop from the top");
RNA_def_property_ui_range(prop, 0, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceCrop_update");
prop = RNA_def_property(srna, "min_y", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "bottom");
- RNA_def_property_ui_text(prop, "Bottom", "");
+ RNA_def_property_ui_text(prop, "Bottom", "Number of pixels to crop from the bottom");
RNA_def_property_ui_range(prop, 0, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceCrop_update");
prop = RNA_def_property(srna, "min_x", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "left");
- RNA_def_property_ui_text(prop, "Left", "");
+ RNA_def_property_ui_text(prop, "Left", "Number of pixels to crop from the left side");
RNA_def_property_ui_range(prop, 0, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceCrop_update");
prop = RNA_def_property(srna, "max_x", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "right");
- RNA_def_property_ui_text(prop, "Right", "");
+ RNA_def_property_ui_text(prop, "Right", "Number of pixels to crop from the right side");
RNA_def_property_ui_range(prop, 0, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceCrop_update");
@@ -1156,13 +1157,13 @@ static void rna_def_strip_transform(BlenderRNA *brna)
prop = RNA_def_property(srna, "offset_x", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "xofs");
- RNA_def_property_ui_text(prop, "Offset X", "");
+ RNA_def_property_ui_text(prop, "Offset X", "Amount to move the input on the X axis within its boundaries");
RNA_def_property_ui_range(prop, -4096, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update");
prop = RNA_def_property(srna, "offset_y", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "yofs");
- RNA_def_property_ui_text(prop, "Offset Y", "");
+ RNA_def_property_ui_text(prop, "Offset Y", "Amount to move the input on the Y axis within its boundaries");
RNA_def_property_ui_range(prop, -4096, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update");
@@ -1246,7 +1247,7 @@ static void rna_def_strip_proxy(BlenderRNA *brna)
prop = RNA_def_property(srna, "timecode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "tc");
RNA_def_property_enum_items(prop, seq_tc_items);
- RNA_def_property_ui_text(prop, "Timecode", "");
+ RNA_def_property_ui_text(prop, "Timecode", "Method for reading the inputs timecode");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_tcindex_update");
prop = RNA_def_property(srna, "use_proxy_custom_directory", PROP_BOOLEAN, PROP_NONE);
@@ -1289,17 +1290,17 @@ static void rna_def_color_balance(BlenderRNA *brna)
prop = RNA_def_property(srna, "invert_gain", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_GAIN);
- RNA_def_property_ui_text(prop, "Inverse Gain", "");
+ RNA_def_property_ui_text(prop, "Inverse Gain", "Invert the gain color`");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
prop = RNA_def_property(srna, "invert_gamma", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_GAMMA);
- RNA_def_property_ui_text(prop, "Inverse Gamma", "");
+ RNA_def_property_ui_text(prop, "Inverse Gamma", "Invert the gamma color");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
prop = RNA_def_property(srna, "invert_lift", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_LIFT);
- RNA_def_property_ui_text(prop, "Inverse Lift", "");
+ RNA_def_property_ui_text(prop, "Inverse Lift", "Invert the lift color");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
/* not yet used */
@@ -1357,10 +1358,10 @@ static void rna_def_sequence_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new modifier");
parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the modifier");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* modifier to add */
parm = RNA_def_enum(func, "type", rna_enum_sequence_modifier_type_items, seqModifierType_ColorBalance, "", "Modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "modifier", "SequenceModifier", "", "Newly created modifier");
RNA_def_function_return(func, parm);
@@ -1371,8 +1372,8 @@ static void rna_def_sequence_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove an existing modifier from the sequence");
/* modifier to remove */
parm = RNA_def_pointer(func, "modifier", "SequenceModifier", "", "Modifier 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* clear all modifiers */
func = RNA_def_function(srna, "clear", "rna_Sequence_modifier_clear");
@@ -1453,13 +1454,13 @@ static void rna_def_sequence(BlenderRNA *brna)
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_MUTE);
RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, true);
- RNA_def_property_ui_text(prop, "Mute", "");
+ RNA_def_property_ui_text(prop, "Mute", "Disable strip so that it cannot be viewed in the output");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_mute_update");
prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_LOCK);
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, true);
- RNA_def_property_ui_text(prop, "Lock", "Lock strip so that it can't be transformed");
+ RNA_def_property_ui_text(prop, "Lock", "Lock strip so that it cannot be transformed");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
/* strip positioning */
@@ -1481,7 +1482,7 @@ static void rna_def_sequence(BlenderRNA *brna)
prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "start");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Start Frame", "");
+ RNA_def_property_ui_text(prop, "Start Frame", "X position where the strip begins");
RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_start_frame_set", NULL); /* overlap tests and calc_seq_disp */
RNA_def_property_editable_func(prop, "rna_Sequence_frame_editable");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
@@ -1552,12 +1553,12 @@ static void rna_def_sequence(BlenderRNA *brna)
prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "blend_mode");
RNA_def_property_enum_items(prop, blend_mode_items);
- RNA_def_property_ui_text(prop, "Blend Mode", "");
+ RNA_def_property_ui_text(prop, "Blend Mode", "Method for controlling how the strip combines with other strips");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "blend_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Blend Opacity", "");
+ RNA_def_property_ui_text(prop, "Blend Opacity", "Percentage of how much the strip's colors affect other strips");
/* stupid 0-100 -> 0-1 */
RNA_def_property_float_funcs(prop, "rna_Sequence_opacity_get", "rna_Sequence_opacity_set", NULL);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
@@ -1566,7 +1567,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_float_sdna(prop, NULL, "effect_fader");
- RNA_def_property_ui_text(prop, "Effect fader position", "");
+ RNA_def_property_ui_text(prop, "Effect fader position", "Custom fade value");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "use_default_fade", PROP_BOOLEAN, PROP_NONE);
@@ -1674,7 +1675,7 @@ static void rna_def_filter_video(StructRNA *srna)
prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_FILTERY);
- RNA_def_property_ui_text(prop, "De-Interlace", "For video movies to remove fields");
+ RNA_def_property_ui_text(prop, "Deinterlace", "Remove fields from video movies");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update_reopen_files");
prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE);
@@ -1714,7 +1715,7 @@ static void rna_def_filter_video(StructRNA *srna)
RNA_def_property_range(prop, 0.0f, 20.0f);
RNA_def_property_ui_range(prop, 0.0f, 2.0f, 3, 3);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Saturation", "");
+ RNA_def_property_ui_text(prop, "Saturation", "Adjust the intensity of the input's color");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "strobe", PROP_FLOAT, PROP_NONE);
@@ -2205,13 +2206,13 @@ static void rna_def_transform(StructRNA *srna)
prop = RNA_def_property(srna, "scale_start_x", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "ScalexIni");
- RNA_def_property_ui_text(prop, "Scale X", "");
+ RNA_def_property_ui_text(prop, "Scale X", "Amount to scale the input in the X axis");
RNA_def_property_ui_range(prop, 0, 10, 3, 6);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "scale_start_y", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "ScaleyIni");
- RNA_def_property_ui_text(prop, "Scale Y", "");
+ RNA_def_property_ui_text(prop, "Scale Y", "Amount to scale the input in the Y axis");
RNA_def_property_ui_range(prop, 0, 10, 3, 6);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
@@ -2222,33 +2223,33 @@ static void rna_def_transform(StructRNA *srna)
prop = RNA_def_property(srna, "translate_start_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xIni");
- RNA_def_property_ui_text(prop, "Translate X", "");
+ RNA_def_property_ui_text(prop, "Translate X", "Amount to move the input on the X axis");
RNA_def_property_ui_range(prop, -4000.0f, 4000.0f, 3, 6);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "translate_start_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "yIni");
- RNA_def_property_ui_text(prop, "Translate Y", "");
+ RNA_def_property_ui_text(prop, "Translate Y", "Amount to move the input on the Y axis");
RNA_def_property_ui_range(prop, -4000.0f, 4000.0f, 3, 6);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "rotation_start", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rotIni");
RNA_def_property_range(prop, -360.0f, 360.0f);
- RNA_def_property_ui_text(prop, "Rotation", "");
+ RNA_def_property_ui_text(prop, "Rotation", "Degrees to rotate the input");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "translation_unit", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "percent");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* not meant to be animated */
RNA_def_property_enum_items(prop, translation_unit_items);
- RNA_def_property_ui_text(prop, "Translation Unit", "");
+ RNA_def_property_ui_text(prop, "Translation Unit", "Unit of measure to translate the input");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, interpolation_items);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* not meant to be animated */
- RNA_def_property_ui_text(prop, "Interpolation", "");
+ RNA_def_property_ui_text(prop, "Interpolation", "Method to determine how missing pixels are created");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
}
@@ -2260,7 +2261,7 @@ static void rna_def_solid_color(StructRNA *srna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "col");
- RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_ui_text(prop, "Color", "Effect Strip color");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
}
@@ -2333,7 +2334,7 @@ static void rna_def_text(StructRNA *srna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "color");
- RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_ui_text(prop, "Color", "Text color");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR_GAMMA);
@@ -2358,13 +2359,13 @@ static void rna_def_text(StructRNA *srna)
prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align");
RNA_def_property_enum_items(prop, text_align_x_items);
- RNA_def_property_ui_text(prop, "Align X", "");
+ RNA_def_property_ui_text(prop, "Align X", "Align the text along the X axis");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
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, text_align_y_items);
- RNA_def_property_ui_text(prop, "Align Y", "");
+ RNA_def_property_ui_text(prop, "Align Y", "Align the image along the Y axis");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "text", PROP_STRING, PROP_NONE);
@@ -2512,7 +2513,7 @@ static void rna_def_colorbalance_modifier(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "color_multiply");
RNA_def_property_range(prop, 0.0f, 20.0f);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Multiply Colors", "");
+ RNA_def_property_ui_text(prop, "Multiply Colors", "Multiply the intensity of each pixel");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
}
@@ -2576,13 +2577,13 @@ static void rna_def_brightcontrast_modifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "bright", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "bright");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
- RNA_def_property_ui_text(prop, "Bright", "");
+ RNA_def_property_ui_text(prop, "Bright", "Adjust the luminosity of the colors");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
prop = RNA_def_property(srna, "contrast", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "contrast");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
- RNA_def_property_ui_text(prop, "Contrast", "");
+ RNA_def_property_ui_text(prop, "Contrast", "Adjust the difference in luminosity between pixels");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
}
@@ -2599,13 +2600,12 @@ static void rna_def_tonemap_modifier(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SequencerTonemapModifierData", "SequenceModifier");
RNA_def_struct_sdna(srna, "SequencerTonemapModifierData");
- RNA_def_struct_ui_text(srna, "SequencerTonemapModifierData",
- "Tone mapping modifier");
+ RNA_def_struct_ui_text(srna, "SequencerTonemapModifierData", "Tone mapping modifier");
prop = RNA_def_property(srna, "tonemap_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, type_items);
- RNA_def_property_ui_text(prop, "Tonemap Type", "");
+ RNA_def_property_ui_text(prop, "Tonemap Type", "Tone mapping algorithm");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
prop = RNA_def_property(srna, "key", PROP_FLOAT, PROP_FACTOR);
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 13fda02c7c8..76f5a4934cf 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -414,14 +414,14 @@ void RNA_api_sequence_strip(StructRNA *srna)
RNA_def_function_ui_description(func, "Return the strip element from a given frame or None");
parm = RNA_def_int(func, "frame", 0, -MAXFRAME, MAXFRAME, "Frame",
"The frame to get the strip element from", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_return(func, RNA_def_pointer(func, "elem", "SequenceElement", "",
"strip element of the current frame"));
func = RNA_def_function(srna, "swap", "rna_Sequence_swap_internal");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "other", "Sequence", "Other", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
}
void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop)
@@ -439,7 +439,7 @@ void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Push an image from ImageSequence.directory");
parm = RNA_def_string(func, "filename", "File", 0, "", "Filepath to image");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "elem", "SequenceElement", "", "New SequenceElement");
RNA_def_function_return(func, parm);
@@ -448,7 +448,7 @@ void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Pop an image off the collection");
parm = RNA_def_int(func, "index", -1, INT_MIN, INT_MAX, "", "Index of image to remove", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
@@ -487,15 +487,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new movie clip sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to add");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -504,15 +504,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new mask sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to add");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -521,15 +521,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new scene sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to add");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -538,15 +538,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new image sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "filepath", "File", 0, "", "Filepath to image");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -555,15 +555,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new movie sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "filepath", "File", 0, "", "Filepath to movie");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -572,15 +572,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID | FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Add a new sound sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "filepath", "File", 0, "", "Filepath to movie");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -589,17 +589,17 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new effect sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", seq_effect_items, 0, "Type",
"type for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
/* don't use MAXFRAME since it makes importer scripts fail */
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, INT_MIN, INT_MAX, "",
"The start frame for the new sequence", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "frame_end", 0, INT_MIN, INT_MAX, "",
"The end frame for the new sequence", INT_MIN, INT_MAX);
RNA_def_pointer(func, "seq1", "Sequence", "", "Sequence 1 for effect");
@@ -614,8 +614,8 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a Sequence");
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "Sequence 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 15950e67671..8ac7aef0d93 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -841,14 +841,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
{FLUID_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"},
{FLUID_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"},
{FLUID_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"},
- {FLUID_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"},
+ {FLUID_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"},
{FLUID_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"},
{FLUID_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"},
{FLUID_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"},
{FLUID_FIELD_VELOCITY_X, "VELOCITY_X", 0, "X Velocity", "X component of the velocity field"},
{FLUID_FIELD_VELOCITY_Y, "VELOCITY_Y", 0, "Y Velocity", "Y component of the velocity field"},
{FLUID_FIELD_VELOCITY_Z, "VELOCITY_Z", 0, "Z Velocity", "Z component of the velocity field"},
- {0, NULL, 0, NULL, NULL}
+ {0, NULL, 0, NULL, NULL}
};
prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index b262e6412e3..724eeccd108 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -71,10 +71,10 @@ EnumPropertyItem rna_enum_space_type_items[] = {
{SPACE_NLA, "NLA_EDITOR", ICON_NLA, "NLA Editor", "Combine and layer Actions"},
{0, "", ICON_NONE, NULL, NULL},
{SPACE_IMAGE, "IMAGE_EDITOR", ICON_IMAGE_COL, "UV/Image Editor", "View and edit images and UV Maps"},
- {SPACE_SEQ, "SEQUENCE_EDITOR", ICON_SEQUENCE, "Video Sequence Editor", "Video editing tools"},
{SPACE_CLIP, "CLIP_EDITOR", ICON_CLIP, "Movie Clip Editor", "Motion tracking tools"},
- {SPACE_TEXT, "TEXT_EDITOR", ICON_TEXT, "Text Editor", "Edit scripts and in-file documentation"},
+ {SPACE_SEQ, "SEQUENCE_EDITOR", ICON_SEQUENCE, "Video Sequence Editor", "Video editing tools"},
{SPACE_NODE, "NODE_EDITOR", ICON_NODETREE, "Node Editor", "Editor for node-based shading and compositing tools"},
+ {SPACE_TEXT, "TEXT_EDITOR", ICON_TEXT, "Text Editor", "Edit scripts and in-file documentation"},
{SPACE_LOGIC, "LOGIC_EDITOR", ICON_LOGIC, "Logic Editor", "Game logic editing"},
{0, "", ICON_NONE, NULL, NULL},
{SPACE_BUTS, "PROPERTIES", ICON_BUTS, "Properties", "Edit properties of active object and related data-blocks"},
@@ -492,7 +492,7 @@ static void rna_View3D_CursorLocation_get(PointerRNA *ptr, float *values)
bScreen *sc = (bScreen *)ptr->id.data;
Scene *scene = (Scene *)sc->scene;
const float *loc = ED_view3d_cursor3d_get(scene, v3d);
-
+
copy_v3_v3(values, loc);
}
@@ -502,7 +502,7 @@ static void rna_View3D_CursorLocation_set(PointerRNA *ptr, const float *values)
bScreen *sc = (bScreen *)ptr->id.data;
Scene *scene = (Scene *)sc->scene;
float *cursor = ED_view3d_cursor3d_get(scene, v3d);
-
+
copy_v3_v3(cursor, values);
}
@@ -518,7 +518,7 @@ static float rna_View3D_GridScaleUnit_get(PointerRNA *ptr)
static void rna_SpaceView3D_layer_set(PointerRNA *ptr, const int *values)
{
View3D *v3d = (View3D *)(ptr->data);
-
+
v3d->lay = ED_view3d_scene_layer_set(v3d->lay, values, &v3d->layact);
}
@@ -545,16 +545,16 @@ static void rna_SpaceView3D_viewport_shade_update(Main *bmain, Scene *scene, Poi
static void rna_SpaceView3D_matcap_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
View3D *v3d = (View3D *)(ptr->data);
-
+
if (v3d->defmaterial) {
Material *ma = v3d->defmaterial;
-
+
if (ma->preview)
BKE_previewimg_free(&ma->preview);
-
+
if (ma->gpumaterial.first)
GPU_material_free(&ma->gpumaterial);
-
+
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ma);
}
}
@@ -562,7 +562,7 @@ static void rna_SpaceView3D_matcap_update(Main *UNUSED(bmain), Scene *UNUSED(sce
static void rna_SpaceView3D_matcap_enable(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
View3D *v3d = (View3D *)(ptr->data);
-
+
if (v3d->matcap_icon < ICON_MATCAP_01 ||
v3d->matcap_icon > ICON_MATCAP_24)
{
@@ -719,7 +719,7 @@ static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C
{
Scene *scene = ((bScreen *)ptr->id.data)->scene;
RenderEngineType *type = RE_engines_find(scene->r.engine);
-
+
EnumPropertyItem *item = NULL;
int totitem = 0;
@@ -728,7 +728,7 @@ static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C
RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_SOLID);
RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_TEXTURE);
RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_MATERIAL);
-
+
if (type && type->view_draw)
RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_RENDER);
@@ -844,7 +844,7 @@ static EnumPropertyItem *rna_SpaceImageEditor_draw_channels_itemf(bContext *UNUS
int zbuf, alpha, totitem = 0;
ibuf = ED_space_image_acquire_buffer(sima, &lock);
-
+
alpha = ibuf && (ibuf->channels == 4);
zbuf = ibuf && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1));
@@ -895,14 +895,14 @@ static void rna_SpaceImageEditor_zoom_get(PointerRNA *ptr, float *values)
static void rna_SpaceImageEditor_cursor_location_get(PointerRNA *ptr, float *values)
{
SpaceImage *sima = (SpaceImage *)ptr->data;
-
+
if (sima->flag & SI_COORDFLOATS) {
copy_v2_v2(values, sima->cursor);
}
else {
int w, h;
ED_space_image_get_size(sima, &w, &h);
-
+
values[0] = sima->cursor[0] * w;
values[1] = sima->cursor[1] * h;
}
@@ -911,14 +911,14 @@ static void rna_SpaceImageEditor_cursor_location_get(PointerRNA *ptr, float *val
static void rna_SpaceImageEditor_cursor_location_set(PointerRNA *ptr, const float *values)
{
SpaceImage *sima = (SpaceImage *)ptr->data;
-
+
if (sima->flag & SI_COORDFLOATS) {
copy_v2_v2(sima->cursor, values);
}
else {
int w, h;
ED_space_image_get_size(sima, &w, &h);
-
+
sima->cursor[0] = values[0] / w;
sima->cursor[1] = values[1] / h;
}
@@ -947,7 +947,7 @@ static void rna_SpaceImageEditor_scopes_update(struct bContext *C, struct Pointe
SpaceImage *sima = (SpaceImage *)ptr->data;
ImBuf *ibuf;
void *lock;
-
+
ibuf = ED_space_image_acquire_buffer(sima, &lock);
if (ibuf) {
ED_space_image_scopes_update(C, sima, ibuf, true);
@@ -1026,12 +1026,12 @@ static void rna_SpaceProperties_pin_id_update(Main *UNUSED(bmain), Scene *UNUSED
{
SpaceButs *sbuts = (SpaceButs *)(ptr->data);
ID *id = sbuts->pinid;
-
+
if (id == NULL) {
sbuts->flag &= ~SB_PIN_CONTEXT;
return;
}
-
+
switch (GS(id->name)) {
case ID_MA:
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, NULL);
@@ -1045,6 +1045,8 @@ static void rna_SpaceProperties_pin_id_update(Main *UNUSED(bmain), Scene *UNUSED
case ID_LA:
WM_main_add_notifier(NC_LAMP, NULL);
break;
+ default:
+ break;
}
}
@@ -1052,7 +1054,7 @@ static void rna_SpaceProperties_pin_id_update(Main *UNUSED(bmain), Scene *UNUSED
static void rna_SpaceProperties_context_set(PointerRNA *ptr, int value)
{
SpaceButs *sbuts = (SpaceButs *)(ptr->data);
-
+
sbuts->mainb = value;
sbuts->mainbuser = value;
}
@@ -1130,7 +1132,8 @@ static EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSED(C),
static void rna_SpaceProperties_context_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
SpaceButs *sbuts = (SpaceButs *)(ptr->data);
- if (ELEM(sbuts->mainb, BCONTEXT_WORLD, BCONTEXT_MATERIAL, BCONTEXT_TEXTURE)) {
+ /* XXX BCONTEXT_DATA is ugly, but required for lamps... See T51318. */
+ if (ELEM(sbuts->mainb, BCONTEXT_WORLD, BCONTEXT_MATERIAL, BCONTEXT_TEXTURE, BCONTEXT_DATA)) {
sbuts->preview = 1;
}
}
@@ -1203,7 +1206,7 @@ static void rna_ConsoleLine_body_set(PointerRNA *ptr, const char *value)
{
ConsoleLine *ci = (ConsoleLine *)ptr->data;
int len = strlen(value);
-
+
if ((len >= ci->len_alloc) || (len * 2 < ci->len_alloc) ) { /* allocate a new string */
MEM_freeN(ci->line);
ci->line = MEM_mallocN((len + 1) * sizeof(char), "rna_consoleline");
@@ -1231,7 +1234,7 @@ static void rna_SpaceDopeSheetEditor_action_set(PointerRNA *ptr, PointerRNA valu
{
SpaceAction *saction = (SpaceAction *)(ptr->data);
bAction *act = (bAction *)value.data;
-
+
if ((act == NULL) || (act->idroot == 0)) {
/* just set if we're clearing the action or if the action is "amorphous" still */
saction->action = act;
@@ -1268,7 +1271,7 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, Po
/* we must set this action to be the one used by active object (if not pinned) */
if (obact /* && saction->pin == 0*/) {
AnimData *adt = NULL;
-
+
if (saction->mode == SACTCONT_ACTION) {
/* TODO: context selector could help decide this with more control? */
adt = BKE_animdata_add_id(&obact->id); /* this only adds if non-existent */
@@ -1278,7 +1281,7 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, Po
if (key)
adt = BKE_animdata_add_id(&key->id); /* this only adds if non-existent */
}
-
+
/* set action */
// FIXME: this overlaps a lot with the BKE_animdata_set_action() API method
if (adt) {
@@ -1286,11 +1289,11 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, Po
if (adt->action != saction->action) {
/* NLA Tweak Mode needs special handling... */
if (adt->flag & ADT_NLA_EDIT_ON) {
- /* Exit editmode first - we cannot change actions while in tweakmode
+ /* Exit editmode first - we cannot change actions while in tweakmode
* NOTE: This will clear the action ref properly
*/
BKE_nla_tweakmode_exit(adt);
-
+
/* Assign new action, and adjust the usercounts accordingly */
adt->action = saction->action;
id_us_plus((ID *)adt->action);
@@ -1300,7 +1303,7 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, Po
if (adt->action) {
/* Fix id-count of action we're replacing */
id_us_min(&adt->action->id);
-
+
/* To prevent data loss (i.e. if users flip between actions using the Browse menu),
* stash this action if nothing else uses it.
*
@@ -1317,17 +1320,17 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, Po
BKE_nla_action_stash(adt);
}
}
-
+
/* Assign new action, and adjust the usercounts accordingly */
adt->action = saction->action;
id_us_plus((ID *)adt->action);
}
}
-
+
/* Force update of animdata */
adt->recalc |= ADT_RECALC_ANIM;
}
-
+
/* force depsgraph flush too */
DAG_id_tag_update(&obact->id, OB_RECALC_OB | OB_RECALC_DATA);
/* Update relations as well, so new time source dependency is added. */
@@ -1339,17 +1342,17 @@ static void rna_SpaceDopeSheetEditor_mode_update(Main *UNUSED(bmain), Scene *sce
{
SpaceAction *saction = (SpaceAction *)(ptr->data);
Object *obact = (scene->basact) ? scene->basact->object : NULL;
-
+
/* special exceptions for ShapeKey Editor mode */
if (saction->mode == SACTCONT_SHAPEKEY) {
Key *key = BKE_key_from_object(obact);
-
+
/* 1) update the action stored for the editor */
if (key)
saction->action = (key->adt) ? key->adt->action : NULL;
else
saction->action = NULL;
-
+
/* 2) enable 'show sliders' by default, since one of the main
* points of the ShapeKey Editor is to provide a one-stop shop
* for controlling the shapekeys, whose main control is the value
@@ -1365,7 +1368,7 @@ static void rna_SpaceDopeSheetEditor_mode_update(Main *UNUSED(bmain), Scene *sce
else
saction->action = NULL;
}
-
+
/* recalculate extents of channel list */
saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
}
@@ -1375,7 +1378,7 @@ static void rna_SpaceDopeSheetEditor_mode_update(Main *UNUSED(bmain), Scene *sce
static void rna_SpaceGraphEditor_display_mode_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
ScrArea *sa = rna_area_from_space(ptr);
-
+
/* after changing view mode, must force recalculation of F-Curve colors
* which can only be achieved using refresh as opposed to redraw
*/
@@ -1465,7 +1468,7 @@ static int rna_SpaceNodeEditor_node_tree_poll(PointerRNA *ptr, const PointerRNA
{
SpaceNode *snode = (SpaceNode *)ptr->data;
bNodeTree *ntree = (bNodeTree *)value.data;
-
+
/* node tree type must match the selected type in node editor */
return (STREQ(snode->tree_idname, ntree->idname));
}
@@ -1544,7 +1547,7 @@ static void rna_SpaceNodeEditor_show_backdrop_update(Main *UNUSED(bmain), Scene
static void rna_SpaceNodeEditor_cursor_location_from_region(SpaceNode *snode, bContext *C, int x, int y)
{
ARegion *ar = CTX_wm_region(C);
-
+
UI_view2d_region_to_view(&ar->v2d, x, y, &snode->cursor[0], &snode->cursor[1]);
snode->cursor[0] /= UI_DPI_FAC;
snode->cursor[1] /= UI_DPI_FAC;
@@ -1896,12 +1899,12 @@ static void rna_def_space(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "Space", NULL);
RNA_def_struct_sdna(srna, "SpaceLink");
RNA_def_struct_ui_text(srna, "Space", "Space data for a screen area");
RNA_def_struct_refine_func(srna, "rna_Space_refine");
-
+
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spacetype");
RNA_def_property_enum_items(prop, rna_enum_space_type_items);
@@ -2102,28 +2105,28 @@ static void rna_def_space_outliner(BlenderRNA *brna)
"Display data-blocks which are unused and/or will be lost when the file is reloaded"},
{0, NULL, 0, NULL, NULL}
};
-
+
srna = RNA_def_struct(brna, "SpaceOutliner", "Space");
RNA_def_struct_sdna(srna, "SpaceOops");
RNA_def_struct_ui_text(srna, "Space Outliner", "Outliner space data");
-
+
prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "outlinevis");
RNA_def_property_enum_items(prop, display_mode_items);
RNA_def_property_ui_text(prop, "Display Mode", "Type of information to display");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
-
+
prop = RNA_def_property(srna, "filter_text", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "search_string");
RNA_def_property_ui_text(prop, "Display Filter", "Live search filtering string");
RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
-
+
prop = RNA_def_property(srna, "use_filter_case_sensitive", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "search_flags", SO_FIND_CASE_SENSITIVE);
RNA_def_property_ui_text(prop, "Case Sensitive Matches Only", "Only use case sensitive matches of search string");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
-
+
prop = RNA_def_property(srna, "use_filter_complete", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "search_flags", SO_FIND_COMPLETE);
RNA_def_property_ui_text(prop, "Complete Matches Only", "Only use complete matches of search string");
@@ -2219,17 +2222,17 @@ static void rna_def_background_image(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "cuser");
RNA_def_property_ui_text(prop, "Clip User", "Parameters defining which frame of the movie clip is displayed");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "offset_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xof");
RNA_def_property_ui_text(prop, "X Offset", "Offset image horizontally from the world origin");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "offset_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "yof");
RNA_def_property_ui_text(prop, "Y Offset", "Offset image vertically from the world origin");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "size");
RNA_def_property_float_funcs(prop, "rna_BackgroundImage_size_get", "rna_BackgroundImage_size_set", NULL);
@@ -2320,8 +2323,8 @@ static void rna_def_backgroundImages(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove background image");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "image", "BackgroundImage", "", "Image displayed as viewport background");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "clear", "rna_BackgroundImage_clear");
RNA_def_function_ui_description(func, "Remove all background images");
@@ -2349,7 +2352,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
{RV3D_CAMOB, "CAMERA", 0, "Camera", ""},
{0, NULL, 0, NULL, NULL}
};
-
+
static EnumPropertyItem bundle_drawtype_items[] = {
{OB_PLAINAXES, "PLAIN_AXES", 0, "Plain Axes", ""},
{OB_ARROWS, "ARROWS", 0, "Arrows", ""},
@@ -2360,7 +2363,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
{OB_EMPTY_CONE, "CONE", 0, "Cone", ""},
{0, NULL, 0, NULL, NULL}
};
-
+
static EnumPropertyItem view3d_matcap_items[] = {
{ICON_MATCAP_01, "01", ICON_MATCAP_01, "", ""},
{ICON_MATCAP_02, "02", ICON_MATCAP_02, "", ""},
@@ -2388,11 +2391,11 @@ static void rna_def_space_view3d(BlenderRNA *brna)
{ICON_MATCAP_24, "24", ICON_MATCAP_24, "", ""},
{0, NULL, 0, NULL, NULL}
};
-
+
srna = RNA_def_struct(brna, "SpaceView3D", "Space");
RNA_def_struct_sdna(srna, "View3D");
RNA_def_struct_ui_text(srna, "3D View Space", "3D View space data");
-
+
prop = RNA_def_property(srna, "camera", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_sdna(prop, NULL, "camera");
@@ -2437,7 +2440,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "ob_centre");
RNA_def_property_ui_text(prop, "Lock to Object", "3D View center is locked to this object's position");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "lock_bone", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "ob_centre_bone");
RNA_def_property_ui_text(prop, "Lock to Bone", "3D View center is locked to this bone's position");
@@ -2460,7 +2463,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "localvd");
RNA_def_property_ui_text(prop, "Local View",
"Display an isolated sub-set of objects, apart from the scene visibility");
-
+
prop = RNA_def_property(srna, "cursor_location", PROP_FLOAT, PROP_XYZ_LENGTH);
RNA_def_property_array(prop, 3);
RNA_def_property_float_funcs(prop, "rna_View3D_CursorLocation_get", "rna_View3D_CursorLocation_set", NULL);
@@ -2468,13 +2471,13 @@ static void rna_def_space_view3d(BlenderRNA *brna)
"3D cursor location for this view (dependent on local view setting)");
RNA_def_property_ui_range(prop, -10000.0, 10000.0, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "lens", PROP_FLOAT, PROP_UNIT_CAMERA);
RNA_def_property_float_sdna(prop, NULL, "lens");
RNA_def_property_ui_text(prop, "Lens", "Viewport lens angle");
RNA_def_property_range(prop, 1.0f, 250.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "near");
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
@@ -2505,7 +2508,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 1024);
RNA_def_property_int_default(prop, 16);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "grid_subdivisions", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "gridsubdiv");
RNA_def_property_ui_text(prop, "Grid Subdivisions", "Number of subdivisions between grid lines");
@@ -2522,28 +2525,28 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_FLOOR);
RNA_def_property_ui_text(prop, "Display Grid Floor", "Show the ground plane grid in perspective view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "show_axis_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_X);
RNA_def_property_ui_text(prop, "Display X Axis", "Show the X axis line in perspective view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "show_axis_y", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_Y);
RNA_def_property_ui_text(prop, "Display Y Axis", "Show the Y axis line in perspective view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "show_axis_z", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_Z);
RNA_def_property_ui_text(prop, "Display Z Axis", "Show the Z axis line in perspective view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "show_outline_selected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SELECT_OUTLINE);
RNA_def_property_ui_text(prop, "Outline Selected",
"Show an outline highlight around selected objects in non-wireframe views");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "show_all_objects_origin", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_DRAW_CENTERS);
RNA_def_property_ui_text(prop, "All Object Origins",
@@ -2555,7 +2558,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Relationship Lines",
"Show dashed lines indicating parent or constraint relationships");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_GPENCIL);
RNA_def_property_ui_text(prop, "Show Grease Pencil",
@@ -2591,7 +2594,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_RENDER_OVERRIDE);
RNA_def_property_ui_text(prop, "Only Render", "Display only objects which will be rendered");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "show_world", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_SHOW_WORLD);
RNA_def_property_ui_text(prop, "World Background", "Display world colors in the background");
@@ -2621,10 +2624,10 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_enum_items(prop, pivot_items_full);
RNA_def_property_ui_text(prop, "Pivot Point", "Pivot center for rotation/scaling");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_pivot_update");
-
+
prop = RNA_def_property(srna, "use_pivot_point_align", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_ALIGN);
- RNA_def_property_ui_text(prop, "Align", "Manipulate center points (object and pose mode only)");
+ RNA_def_property_ui_text(prop, "Align", "Manipulate center points (object, pose and weight paint mode only)");
RNA_def_property_ui_icon(prop, ICON_ALIGN, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_pivot_update");
@@ -2640,7 +2643,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Transform Manipulators", "Transformation manipulators");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "transform_orientation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "twmode");
RNA_def_property_enum_items(prop, transform_orientation_items);
@@ -2678,7 +2681,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_array(prop, 8);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Local View Layers", "Local view layers visible in this 3D View");
-
+
prop = RNA_def_property(srna, "layers_used", PROP_BOOLEAN, PROP_LAYER_MEMBER);
RNA_def_property_boolean_sdna(prop, NULL, "lay_used", 1);
RNA_def_property_array(prop, 20);
@@ -2730,7 +2733,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SOLID_MATCAP);
RNA_def_property_ui_text(prop, "Matcap", "Active Objects draw images mapped on normals, enhancing Solid Draw Mode");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_matcap_enable");
-
+
prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "matcap_icon");
RNA_def_property_enum_items(prop, view3d_matcap_items);
@@ -2793,17 +2796,17 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "viewlock", RV3D_LOCKED);
RNA_def_property_ui_text(prop, "Lock", "Lock view rotation in side views");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_RegionView3D_quadview_update");
-
+
prop = RNA_def_property(srna, "show_sync_view", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "viewlock", RV3D_BOXVIEW);
RNA_def_property_ui_text(prop, "Box", "Sync view position between side views");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_RegionView3D_quadview_update");
-
+
prop = RNA_def_property(srna, "use_box_clip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "viewlock", RV3D_BOXCLIP);
RNA_def_property_ui_text(prop, "Clip", "Clip objects based on what's visible in other side views");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_RegionView3D_quadview_clip_update");
-
+
prop = RNA_def_property(srna, "perspective_matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "persmat");
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* XXX: for now, it's too risky for users to do this */
@@ -2816,7 +2819,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
RNA_def_property_ui_text(prop, "Window Matrix", "Current window matrix");
-
+
prop = RNA_def_property(srna, "view_matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "viewmat");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
@@ -2834,7 +2837,17 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "is_persp", 1);
RNA_def_property_ui_text(prop, "Is Perspective", "");
RNA_def_property_flag(prop, PROP_EDITABLE);
-
+
+ /* This isn't directly accessible from the UI, only an operator. */
+ prop = RNA_def_property(srna, "use_clip_planes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "rflag", RV3D_CLIPPING);
+ RNA_def_property_ui_text(prop, "Use Clip Planes", "");
+
+ prop = RNA_def_property(srna, "clip_planes", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "clip");
+ RNA_def_property_multi_array(prop, 2, (int[]){6, 4});
+ RNA_def_property_ui_text(prop, "Clip Planes", "");
+
prop = RNA_def_property(srna, "view_location", PROP_FLOAT, PROP_TRANSLATION);
#if 0
RNA_def_property_float_sdna(prop, NULL, "ofs"); /* cant use because its negated */
@@ -2846,7 +2859,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "View Location", "View pivot location");
RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, NC_WINDOW, NULL);
-
+
prop = RNA_def_property(srna, "view_rotation", PROP_FLOAT, PROP_QUATERNION); /* cant use because its inverted */
#if 0
RNA_def_property_float_sdna(prop, NULL, "viewquat");
@@ -2857,7 +2870,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
#endif
RNA_def_property_ui_text(prop, "View Rotation", "Rotation in quaternions (keep normalized)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
/* not sure we need rna access to these but adding anyway */
prop = RNA_def_property(srna, "view_distance", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "dist");
@@ -2893,14 +2906,14 @@ static void rna_def_space_buttons(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SpaceProperties", "Space");
RNA_def_struct_sdna(srna, "SpaceButs");
RNA_def_struct_ui_text(srna, "Properties Space", "Properties space data");
-
+
prop = RNA_def_property(srna, "context", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mainb");
RNA_def_property_enum_items(prop, buttons_context_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_SpaceProperties_context_set", "rna_SpaceProperties_context_itemf");
RNA_def_property_ui_text(prop, "Context", "Type of active data to display and edit");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_SpaceProperties_context_update");
-
+
prop = RNA_def_property(srna, "align", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align");
RNA_def_property_enum_items(prop, align_items);
@@ -2988,7 +3001,7 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_SpaceImageEditor_zoom_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Zoom", "Zoom factor");
-
+
/* image draw */
prop = RNA_def_property(srna, "show_repeat", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAW_TILE);
@@ -3020,7 +3033,7 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "SpaceUVEditor");
RNA_def_property_pointer_funcs(prop, "rna_SpaceImageEditor_uvedit_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "UV Editor", "UV editor settings");
-
+
/* mode */
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
@@ -3050,7 +3063,7 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this space");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
-
+
/* update */
prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "lock", 0);
@@ -3089,7 +3102,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
static EnumPropertyItem view_type_items[] = {
{SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""},
{SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Image Preview", ""},
@@ -3143,7 +3156,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SpaceSequenceEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceSeq");
RNA_def_struct_ui_text(srna, "Space Sequence Editor", "Sequence editor space data");
-
+
/* view type, fairly important */
prop = RNA_def_property(srna, "view_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "view");
@@ -3164,17 +3177,17 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Frame Number Indicator",
"Show frame number beside the current frame indicator line");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
prop = RNA_def_property(srna, "show_frames", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_DRAWFRAMES);
RNA_def_property_ui_text(prop, "Draw Frames", "Draw frames rather than seconds");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
prop = RNA_def_property(srna, "use_marker_sync", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_MARKER_TRANS);
RNA_def_property_ui_text(prop, "Sync Markers", "Transform markers as well as strips");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
prop = RNA_def_property(srna, "show_separate_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_DRAW_COLOR_SEPARATED);
RNA_def_property_ui_text(prop, "Separate Colors", "Separate color channels in preview");
@@ -3199,7 +3212,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SEQ_DRAWFRAMES);
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_GPENCIL);
RNA_def_property_ui_text(prop, "Show Grease Pencil",
@@ -3230,14 +3243,14 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Overexposed", "Show overexposed areas with zebra stripes");
RNA_def_property_range(prop, 0, 110);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
prop = RNA_def_property(srna, "proxy_render_size", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "render_size");
RNA_def_property_enum_items(prop, proxy_render_size_items);
RNA_def_property_ui_text(prop, "Proxy render size",
"Draw preview using full resolution or different proxy resolutions");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
/* grease pencil */
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
@@ -3298,7 +3311,7 @@ static void rna_def_space_text(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Syntax Highlight", "Syntax highlight for scripting");
RNA_def_property_ui_icon(prop, ICON_SYNTAX_OFF, 1);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
-
+
prop = RNA_def_property(srna, "show_line_highlight", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "line_hlight", 0);
RNA_def_property_ui_text(prop, "Highlight Line", "Highlight the current line");
@@ -3343,12 +3356,12 @@ static void rna_def_space_text(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "overwrite", 1);
RNA_def_property_ui_text(prop, "Overwrite", "Overwrite characters when typing rather than inserting them");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
-
+
prop = RNA_def_property(srna, "use_live_edit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "live_edit", 1);
RNA_def_property_ui_text(prop, "Live Edit", "Run python while editing");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
-
+
/* find */
prop = RNA_def_property(srna, "use_find_all", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", ST_FIND_ALL);
@@ -3382,7 +3395,7 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
/* XXX: action-editor is currently for object-level only actions, so show that using object-icon hint */
static EnumPropertyItem mode_items[] = {
{SACTCONT_DOPESHEET, "DOPESHEET", ICON_OOPS, "Dope Sheet", "Edit all keyframes in scene"},
@@ -3393,8 +3406,8 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
{SACTCONT_CACHEFILE, "CACHEFILE", ICON_FILE, "Cache File", "Edit timings for Cache File data-blocks"},
{0, NULL, 0, NULL, NULL}
};
-
-
+
+
srna = RNA_def_struct(brna, "SpaceDopeSheetEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceAction");
RNA_def_struct_ui_text(srna, "Space Dope Sheet Editor", "Dope Sheet space data");
@@ -3406,51 +3419,51 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
"rna_Action_actedit_assign_poll");
RNA_def_property_ui_text(prop, "Action", "Action displayed and edited in this space");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_SpaceDopeSheetEditor_action_update");
-
+
/* mode */
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, mode_items);
RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, "rna_SpaceDopeSheetEditor_mode_update");
-
+
/* display */
prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_DRAWTIME);
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
-
+
prop = RNA_def_property(srna, "show_frame_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NODRAWCFRANUM);
RNA_def_property_ui_text(prop, "Show Frame Number Indicator",
"Show frame number beside the current frame indicator line");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
-
+
prop = RNA_def_property(srna, "show_sliders", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_SLIDERS);
RNA_def_property_ui_text(prop, "Show Sliders", "Show sliders beside F-Curve channels");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
-
+
prop = RNA_def_property(srna, "show_pose_markers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_POSEMARKERS_SHOW);
RNA_def_property_ui_text(prop, "Show Pose Markers",
"Show markers belonging to the active action instead of Scene markers "
"(Action and Shape Key Editors only)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
-
+
prop = RNA_def_property(srna, "show_group_colors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NODRAWGCOLORS);
RNA_def_property_ui_text(prop, "Show Group Colors",
"Draw groups and channels with colors matching their corresponding groups "
"(pose bones only currently)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
-
+
/* editing */
prop = RNA_def_property(srna, "use_auto_merge_keyframes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NOTRANSKEYCULL);
RNA_def_property_ui_text(prop, "AutoMerge Keyframes", "Automatically merge nearby keyframes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
-
+
prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NOREALTIMEUPDATES);
RNA_def_property_ui_text(prop, "Realtime Updates",
@@ -3479,14 +3492,14 @@ static void rna_def_space_graph(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
static EnumPropertyItem mode_items[] = {
{SIPO_MODE_ANIMATION, "FCURVES", ICON_IPO, "F-Curve",
"Edit animation/keyframes displayed as 2D curves"},
{SIPO_MODE_DRIVERS, "DRIVERS", ICON_DRIVER, "Drivers", "Edit drivers"},
{0, NULL, 0, NULL, NULL}
};
-
+
/* this is basically the same as the one for the 3D-View, but with some entries omitted */
static EnumPropertyItem gpivot_items[] = {
{V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", ""},
@@ -3497,93 +3510,93 @@ static void rna_def_space_graph(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
-
+
srna = RNA_def_struct(brna, "SpaceGraphEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceIpo");
RNA_def_struct_ui_text(srna, "Space Graph Editor", "Graph Editor space data");
-
+
/* mode */
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, mode_items);
RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, "rna_SpaceGraphEditor_display_mode_update");
-
+
/* display */
prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_DRAWTIME);
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "show_frame_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NODRAWCFRANUM);
RNA_def_property_ui_text(prop, "Show Frame Number Indicator",
"Show frame number beside the current frame indicator line");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "show_sliders", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_SLIDERS);
RNA_def_property_ui_text(prop, "Show Sliders", "Show sliders beside F-Curve channels");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "show_handles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NOHANDLES);
RNA_def_property_ui_text(prop, "Show Handles", "Show handles of Bezier control points");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "use_only_selected_curves_handles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_SELCUVERTSONLY);
RNA_def_property_ui_text(prop, "Only Selected Curve Keyframes",
"Only keyframes of selected F-Curves are visible and editable");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "use_only_selected_keyframe_handles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_SELVHANDLESONLY);
RNA_def_property_ui_text(prop, "Only Selected Keyframes Handles",
"Only show and edit handles of selected keyframes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "use_beauty_drawing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_BEAUTYDRAW_OFF);
RNA_def_property_ui_text(prop, "Use High Quality Drawing",
"Draw F-Curves using Anti-Aliasing and other fancy effects "
"(disable for better performance)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "show_group_colors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NODRAWGCOLORS);
RNA_def_property_ui_text(prop, "Show Group Colors",
"Draw groups and channels with colors matching their corresponding groups");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
/* editing */
prop = RNA_def_property(srna, "use_auto_merge_keyframes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NOTRANSKEYCULL);
RNA_def_property_ui_text(prop, "AutoMerge Keyframes", "Automatically merge nearby keyframes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NOREALTIMEUPDATES);
RNA_def_property_ui_text(prop, "Realtime Updates",
"When transforming keyframes, changes to the animation data are flushed to other views");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
/* cursor */
prop = RNA_def_property(srna, "show_cursor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NODRAWCURSOR);
RNA_def_property_ui_text(prop, "Show Cursor", "Show 2D cursor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "cursor_position_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cursorTime");
RNA_def_property_ui_text(prop, "Cursor X-Value", "Graph Editor 2D-Value cursor - X-Value component");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "cursor_position_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cursorVal");
RNA_def_property_ui_text(prop, "Cursor Y-Value", "Graph Editor 2D-Value cursor - Y-Value component");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "pivot_point", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "around");
RNA_def_property_enum_items(prop, gpivot_items);
@@ -3627,34 +3640,34 @@ static void rna_def_space_nla(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "SpaceNLA", "Space");
RNA_def_struct_sdna(srna, "SpaceNla");
RNA_def_struct_ui_text(srna, "Space Nla Editor", "NLA editor space data");
-
+
/* display */
prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SNLA_DRAWTIME);
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
-
+
prop = RNA_def_property(srna, "show_frame_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NODRAWCFRANUM);
RNA_def_property_ui_text(prop, "Show Frame Number Indicator",
"Show frame number beside the current frame indicator line");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
-
+
prop = RNA_def_property(srna, "show_strip_curves", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOSTRIPCURVES);
RNA_def_property_ui_text(prop, "Show Control F-Curves", "Show influence F-Curves on strips");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
-
+
prop = RNA_def_property(srna, "show_local_markers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOLOCALMARKERS);
RNA_def_property_ui_text(prop, "Show Local Markers",
"Show action-local markers on the strips, useful when synchronizing timing across strips");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
-
+
/* editing */
prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOREALTIMEUPDATES);
@@ -3680,54 +3693,54 @@ static void rna_def_space_time(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "SpaceTimeline", "Space");
RNA_def_struct_sdna(srna, "SpaceTime");
RNA_def_struct_ui_text(srna, "Space Timeline Editor", "Timeline editor space data");
-
+
/* view settings */
prop = RNA_def_property(srna, "show_frame_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TIME_CFRA_NUM);
RNA_def_property_ui_text(prop, "Show Frame Number Indicator",
"Show frame number beside the current frame indicator line");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
+
prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", TIME_DRAWFRAMES);
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
+
/* displaying cache status */
prop = RNA_def_property(srna, "show_cache", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_DISPLAY);
RNA_def_property_ui_text(prop, "Show Cache", "Show the status of cached frames in the timeline");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
+
prop = RNA_def_property(srna, "cache_softbody", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_SOFTBODY);
RNA_def_property_ui_text(prop, "Softbody", "Show the active object's softbody point cache");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
+
prop = RNA_def_property(srna, "cache_particles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_PARTICLES);
RNA_def_property_ui_text(prop, "Particles", "Show the active object's particle point cache");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
+
prop = RNA_def_property(srna, "cache_cloth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_CLOTH);
RNA_def_property_ui_text(prop, "Cloth", "Show the active object's cloth point cache");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
+
prop = RNA_def_property(srna, "cache_smoke", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_SMOKE);
RNA_def_property_ui_text(prop, "Smoke", "Show the active object's smoke cache");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
+
prop = RNA_def_property(srna, "cache_dynamicpaint", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_DYNAMICPAINT);
RNA_def_property_ui_text(prop, "Dynamic Paint", "Show the active object's Dynamic Paint cache");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
+
prop = RNA_def_property(srna, "cache_rigidbody", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_RIGIDBODY);
RNA_def_property_ui_text(prop, "Rigid Body", "Show the active object's Rigid Body cache");
@@ -3746,17 +3759,17 @@ static void rna_def_console_line(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "ConsoleLine", NULL);
RNA_def_struct_ui_text(srna, "Console Input", "Input line for the interactive console");
-
+
prop = RNA_def_property(srna, "body", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_ConsoleLine_body_get", "rna_ConsoleLine_body_length",
"rna_ConsoleLine_body_set");
RNA_def_property_ui_text(prop, "Line", "Text in the line");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CONSOLE, NULL);
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_TEXT);
-
+
prop = RNA_def_property(srna, "current_character", PROP_INT, PROP_NONE); /* copied from text editor */
RNA_def_property_int_sdna(prop, NULL, "cursor");
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_ConsoleLine_cursor_index_range");
@@ -3767,16 +3780,16 @@ static void rna_def_console_line(BlenderRNA *brna)
RNA_def_property_enum_items(prop, console_line_type_items);
RNA_def_property_ui_text(prop, "Type", "Console line type when used in scrollback");
}
-
+
static void rna_def_space_console(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "SpaceConsole", "Space");
RNA_def_struct_sdna(srna, "SpaceConsole");
RNA_def_struct_ui_text(srna, "Space Console", "Interactive python console");
-
+
/* display */
prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_NONE); /* copied from text editor */
RNA_def_property_int_sdna(prop, NULL, "lheight");
@@ -3788,14 +3801,14 @@ static void rna_def_space_console(BlenderRNA *brna)
prop = RNA_def_property(srna, "select_start", PROP_INT, PROP_UNSIGNED); /* copied from text editor */
RNA_def_property_int_sdna(prop, NULL, "sel_start");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CONSOLE, NULL);
-
+
prop = RNA_def_property(srna, "select_end", PROP_INT, PROP_UNSIGNED); /* copied from text editor */
RNA_def_property_int_sdna(prop, NULL, "sel_end");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CONSOLE, NULL);
prop = RNA_def_property(srna, "prompt", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Prompt", "Command line prompt");
-
+
prop = RNA_def_property(srna, "language", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Language", "Command line prompt language");
@@ -3803,7 +3816,7 @@ static void rna_def_space_console(BlenderRNA *brna)
RNA_def_property_collection_sdna(prop, NULL, "history", NULL);
RNA_def_property_struct_type(prop, "ConsoleLine");
RNA_def_property_ui_text(prop, "History", "Command history");
-
+
prop = RNA_def_property(srna, "scrollback", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "scrollback", NULL);
RNA_def_property_struct_type(prop, "ConsoleLine");
@@ -3814,7 +3827,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
static EnumPropertyItem file_display_items[] = {
{FILE_SHORTDISPLAY, "LIST_SHORT", ICON_SHORTDISPLAY, "Short List", "Display files as short list"},
{FILE_LONGDISPLAY, "LIST_LONG", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"},
@@ -4078,7 +4091,7 @@ static void rna_def_space_filebrowser(BlenderRNA *brna)
prop = RNA_def_property(srna, "params", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "params");
RNA_def_property_ui_text(prop, "Filebrowser Parameter", "Parameters and Settings for the Filebrowser");
-
+
prop = RNA_def_property(srna, "active_operator", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "op");
RNA_def_property_ui_text(prop, "Active Operator", "");
@@ -4159,28 +4172,28 @@ static void rna_def_space_info(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SpaceInfo", "Space");
RNA_def_struct_sdna(srna, "SpaceInfo");
RNA_def_struct_ui_text(srna, "Space Info", "Info space data");
-
+
/* reporting display */
prop = RNA_def_property(srna, "show_report_debug", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "rpt_mask", INFO_RPT_DEBUG);
RNA_def_property_ui_text(prop, "Show Debug", "Display debug reporting info");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
-
+
prop = RNA_def_property(srna, "show_report_info", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "rpt_mask", INFO_RPT_INFO);
RNA_def_property_ui_text(prop, "Show Info", "Display general information");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
-
+
prop = RNA_def_property(srna, "show_report_operator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "rpt_mask", INFO_RPT_OP);
RNA_def_property_ui_text(prop, "Show Operator", "Display the operator log");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
-
+
prop = RNA_def_property(srna, "show_report_warning", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "rpt_mask", INFO_RPT_WARN);
RNA_def_property_ui_text(prop, "Show Warn", "Display warnings");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
-
+
prop = RNA_def_property(srna, "show_report_error", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "rpt_mask", INFO_RPT_ERR);
RNA_def_property_ui_text(prop, "Show Error", "Display error text");
@@ -4196,7 +4209,7 @@ static void rna_def_space_userpref(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "SpaceUserPreferences", "Space");
RNA_def_struct_sdna(srna, "SpaceUserPref");
RNA_def_struct_ui_text(srna, "Space User Preferences", "User preferences space data");
@@ -4218,7 +4231,7 @@ static void rna_def_node_tree_path(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "NodeTreePath", NULL);
RNA_def_struct_sdna(srna, "bNodeTreePath");
RNA_def_struct_ui_text(srna, "Node Tree Path", "Element of the node space tree path");
@@ -4253,15 +4266,15 @@ static void rna_def_space_node_path_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Set the root node tree");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "append", "rna_SpaceNodeEditor_path_append");
RNA_def_function_ui_description(func, "Append a node group tree to the path");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "Node tree to append to the node editor path");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "node", "Node", "Node", "Group node linking to this node tree");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
func = RNA_def_function(srna, "pop", "rna_SpaceNodeEditor_path_pop");
RNA_def_function_ui_description(func, "Remove the last node tree from the path");
@@ -4385,7 +4398,7 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", SNODE_AUTO_RENDER);
RNA_def_property_ui_text(prop, "Auto Render", "Re-render and composite changed layers on 3D edits");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
-
+
prop = RNA_def_property(srna, "backdrop_zoom", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "zoom");
RNA_def_property_float_default(prop, 1.0f);
@@ -4393,7 +4406,7 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.01, 100, 1, 2);
RNA_def_property_ui_text(prop, "Backdrop Zoom", "Backdrop zoom factor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
-
+
prop = RNA_def_property(srna, "backdrop_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xof");
RNA_def_property_ui_text(prop, "Backdrop X", "Backdrop X offset");
@@ -4410,11 +4423,6 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Draw Channels", "Channels of the image to draw");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
- prop = RNA_def_property(srna, "show_highlight", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SNODE_SHOW_HIGHLIGHT);
- RNA_def_property_ui_text(prop, "Highlight", "Highlight nodes that are being calculated");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
-
/* the mx/my "cursor" in the node editor is used only by operators to store the mouse position */
prop = RNA_def_property(srna, "cursor_location", PROP_FLOAT, PROP_XYZ);
RNA_def_property_array(prop, 2);
@@ -4453,12 +4461,12 @@ static void rna_def_space_logic(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_SENS_SEL);
RNA_def_property_ui_text(prop, "Show Selected Object", "Show sensors of all selected objects");
RNA_def_property_update(prop, NC_LOGIC, NULL);
-
+
prop = RNA_def_property(srna, "show_sensors_active_object", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_SENS_ACT);
RNA_def_property_ui_text(prop, "Show Active Object", "Show sensors of active object");
RNA_def_property_update(prop, NC_LOGIC, NULL);
-
+
prop = RNA_def_property(srna, "show_sensors_linked_controller", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_SENS_LINK);
RNA_def_property_ui_text(prop, "Show Linked to Controller", "Show linked objects to the controller");
@@ -4474,7 +4482,7 @@ static void rna_def_space_logic(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_CONT_SEL);
RNA_def_property_ui_text(prop, "Show Selected Object", "Show controllers of all selected objects");
RNA_def_property_update(prop, NC_LOGIC, NULL);
-
+
prop = RNA_def_property(srna, "show_controllers_active_object", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_CONT_ACT);
RNA_def_property_ui_text(prop, "Show Active Object", "Show controllers of active object");
@@ -4490,12 +4498,12 @@ static void rna_def_space_logic(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_ACT_SEL);
RNA_def_property_ui_text(prop, "Show Selected Object", "Show actuators of all selected objects");
RNA_def_property_update(prop, NC_LOGIC, NULL);
-
+
prop = RNA_def_property(srna, "show_actuators_active_object", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_ACT_ACT);
RNA_def_property_ui_text(prop, "Show Active Object", "Show actuators of active object");
RNA_def_property_update(prop, NC_LOGIC, NULL);
-
+
prop = RNA_def_property(srna, "show_actuators_linked_controller", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_ACT_LINK);
RNA_def_property_ui_text(prop, "Show Linked to Actuator", "Show linked objects to the actuator");
@@ -4609,7 +4617,7 @@ static void rna_def_space_clip(BlenderRNA *brna)
/* path length */
prop = RNA_def_property(srna, "path_length", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "path_length");
- RNA_def_property_range(prop, 0, 50);
+ RNA_def_property_range(prop, 0, INT_MAX);
RNA_def_property_ui_text(prop, "Path Length", "Length of displaying path, in frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index 3cfbd798ad6..8f771eda99d 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -47,7 +47,7 @@ static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d)
v3d = (View3D *)sa->spacedata.first;
- ED_view3d_update_viewmat(sc->scene, v3d, ar, NULL, NULL);
+ ED_view3d_update_viewmat(sc->scene, v3d, ar, NULL, NULL, NULL);
}
}
@@ -84,9 +84,9 @@ void RNA_api_space_node(StructRNA *srna)
RNA_def_function_ui_description(func, "Set the cursor location using region coordinates");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "x", "Region x coordinate", -10000, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "y", "Region y coordinate", -10000, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_api_space_text(StructRNA *srna)
@@ -98,9 +98,9 @@ void RNA_api_space_text(StructRNA *srna)
RNA_def_function_ui_description(func, "Retrieve the region position from the given line and character position");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_int(func, "line", 0, INT_MIN, INT_MAX, "Line", "Line index", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "column", 0, INT_MIN, INT_MAX, "Column", "Column index", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int_array(func, "result", 2, NULL, -1, INT_MAX, "", "Region coordinates", -1, INT_MAX);
RNA_def_function_output(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_text_api.c b/source/blender/makesrna/intern/rna_text_api.c
index 2478ad0fe1a..0287f74587b 100644
--- a/source/blender/makesrna/intern/rna_text_api.c
+++ b/source/blender/makesrna/intern/rna_text_api.c
@@ -55,15 +55,15 @@ static void rna_Text_write(Text *text, const char *str)
void RNA_api_text(StructRNA *srna)
{
FunctionRNA *func;
- PropertyRNA *prop;
+ PropertyRNA *parm;
func = RNA_def_function(srna, "clear", "rna_Text_clear");
RNA_def_function_ui_description(func, "clear the text block");
func = RNA_def_function(srna, "write", "rna_Text_write");
RNA_def_function_ui_description(func, "write text at the cursor location and advance to the end of the text block");
- prop = RNA_def_string(func, "text", "Text", 0, "", "New text for this data-block");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_string(func, "text", "Text", 0, "", "New text for this data-block");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 1e88585a286..4ad2832b953 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -267,6 +267,8 @@ void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
break;
}
+ default:
+ break;
}
}
diff --git a/source/blender/makesrna/intern/rna_texture_api.c b/source/blender/makesrna/intern/rna_texture_api.c
index ef1ef5e1469..a8fcf0ca3b6 100644
--- a/source/blender/makesrna/intern/rna_texture_api.c
+++ b/source/blender/makesrna/intern/rna_texture_api.c
@@ -93,11 +93,11 @@ void RNA_api_texture(StructRNA *srna)
RNA_def_function_ui_description(func, "Evaluate the texture at the coordinates given");
parm = RNA_def_float_vector(func, "value", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return location and normal */
parm = RNA_def_float_vector(func, "result", 4, NULL, -FLT_MAX, FLT_MAX, "Result", NULL, -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
}
@@ -119,7 +119,7 @@ void RNA_api_environment_map(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
parm = RNA_def_string_file_name(func, "filepath", NULL, FILE_MAX, "File path", "Location of the output file");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_pointer(func, "scene", "Scene", "", "Overrides the scene from which image parameters are taken");
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 2340345c1c6..7a01e3a4f6b 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -1289,7 +1289,7 @@ static void rna_def_trackingMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Get marker for specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to find marker for", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "exact", true, "Exact",
"Get marker at exact frame number rather than get estimated marker");
parm = RNA_def_pointer(func, "marker", "MovieTrackingMarker", "", "Marker for specified frame");
@@ -1299,11 +1299,11 @@ static void rna_def_trackingMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Insert a new marker at the specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to insert marker to", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_float_vector(func, "co", 2, NULL, -1.0, 1.0, "Coordinate",
"Place new marker at the given frame using specified in normalized space coordinates",
-1.0, 1.0);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "marker", "MovieTrackingMarker", "", "Newly created marker");
RNA_def_function_return(func, parm);
@@ -1311,7 +1311,7 @@ static void rna_def_trackingMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Delete marker at specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to delete marker from", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_trackingTrack(BlenderRNA *brna)
@@ -1593,7 +1593,7 @@ static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Get plane marker for specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to find marker for", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "exact", true, "Exact",
"Get plane marker at exact frame number rather than get estimated marker");
parm = RNA_def_pointer(func, "plane_marker", "MovieTrackingPlaneMarker", "", "Plane marker for specified frame");
@@ -1603,7 +1603,7 @@ static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Insert a new plane marker at the specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to insert marker to", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "plane_marker", "MovieTrackingPlaneMarker", "", "Newly created plane marker");
RNA_def_function_return(func, parm);
@@ -1611,7 +1611,7 @@ static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Delete plane marker at specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to delete plane marker from", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_trackingPlaneTrack(BlenderRNA *brna)
@@ -1886,7 +1886,7 @@ static void rna_def_trackingReconstructedCameras(BlenderRNA *brna)
RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to find camera for", MINFRAME, MAXFRAME);
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, -FLT_MAX, FLT_MAX, "Matrix",
"Interpolated camera matrix for a given frame", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
}
@@ -2099,7 +2099,7 @@ static void rna_def_trackingObjects(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_trackingObject_new");
RNA_def_function_ui_description(func, "Add tracking object to this movie clip");
parm = RNA_def_string(func, "name", NULL, 0, "", "Name of new object");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "object", "MovieTrackingObject", "", "New motion tracking object");
RNA_def_function_return(func, parm);
@@ -2107,8 +2107,8 @@ static void rna_def_trackingObjects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove tracking object from this movie clip");
parm = RNA_def_pointer(func, "object", "MovieTrackingObject", "", "Motion tracking object to be removed");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* active object */
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 5f11dd51282..08038b0b1ff 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -177,16 +177,17 @@ static void rna_Panel_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
RNA_struct_free_extension(type, &pt->ext);
+ RNA_struct_free(&BLENDER_RNA, type);
BLI_freelinkN(&art->paneltypes, pt);
- RNA_struct_free(&BLENDER_RNA, type);
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
}
-static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_Panel_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
ARegionType *art;
PanelType *pt, dummypt = {NULL};
@@ -229,6 +230,12 @@ static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *dat
break;
}
}
+ if (!RNA_struct_available_or_report(reports, dummypt.idname)) {
+ return NULL;
+ }
+ if (!RNA_struct_bl_idname_ok_or_report(reports, dummypt.idname, "_PT_")) {
+ return NULL;
+ }
/* create a new panel type */
pt = MEM_callocN(sizeof(PanelType), "python buttons panel");
@@ -455,17 +462,17 @@ static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
RNA_struct_free_extension(type, &ult->ext);
+ RNA_struct_free(&BLENDER_RNA, type);
WM_uilisttype_freelink(ult);
- RNA_struct_free(&BLENDER_RNA, type);
-
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
}
-static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_UIList_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
uiListType *ult, dummyult = {NULL};
uiList dummyuilist = {NULL};
@@ -489,8 +496,15 @@ static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *da
/* check if we have registered this uilist type before, and remove it */
ult = WM_uilisttype_find(dummyult.idname, true);
- if (ult && ult->ext.srna)
+ if (ult && ult->ext.srna) {
rna_UIList_unregister(bmain, ult->ext.srna);
+ }
+ if (!RNA_struct_available_or_report(reports, dummyult.idname)) {
+ return NULL;
+ }
+ if (!RNA_struct_bl_idname_ok_or_report(reports, dummyult.idname, "_UL_")) {
+ return NULL;
+ }
/* create a new menu type */
ult = MEM_callocN(sizeof(uiListType) + over_alloc, "python uilist");
@@ -551,16 +565,17 @@ static void rna_Header_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
RNA_struct_free_extension(type, &ht->ext);
+ RNA_struct_free(&BLENDER_RNA, type);
BLI_freelinkN(&art->headertypes, ht);
- RNA_struct_free(&BLENDER_RNA, type);
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
}
-static StructRNA *rna_Header_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_Header_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
ARegionType *art;
HeaderType *ht, dummyht = {NULL};
@@ -593,6 +608,12 @@ static StructRNA *rna_Header_register(Main *bmain, ReportList *reports, void *da
break;
}
}
+ if (!RNA_struct_available_or_report(reports, dummyht.idname)) {
+ return NULL;
+ }
+ if (!RNA_struct_bl_idname_ok_or_report(reports, dummyht.idname, "_HT_")) {
+ return NULL;
+ }
/* create a new header type */
ht = MEM_callocN(sizeof(HeaderType), "python buttons header");
@@ -673,17 +694,17 @@ static void rna_Menu_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
RNA_struct_free_extension(type, &mt->ext);
+ RNA_struct_free(&BLENDER_RNA, type);
WM_menutype_freelink(mt);
- RNA_struct_free(&BLENDER_RNA, type);
-
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
}
-static StructRNA *rna_Menu_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_Menu_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
MenuType *mt, dummymt = {NULL};
Menu dummymenu = {NULL};
@@ -714,8 +735,15 @@ static StructRNA *rna_Menu_register(Main *bmain, ReportList *reports, void *data
/* check if we have registered this menu type before, and remove it */
mt = WM_menutype_find(dummymt.idname, true);
- if (mt && mt->ext.srna)
+ if (mt && mt->ext.srna) {
rna_Menu_unregister(bmain, mt->ext.srna);
+ }
+ if (!RNA_struct_available_or_report(reports, dummymt.idname)) {
+ return NULL;
+ }
+ if (!RNA_struct_bl_idname_ok_or_report(reports, dummymt.idname, "_MT_")) {
+ return NULL;
+ }
/* create a new menu type */
if (_menu_descr[0]) {
@@ -937,6 +965,7 @@ static void rna_def_panel(BlenderRNA *brna)
RNA_def_struct_refine_func(srna, "rna_Panel_refine");
RNA_def_struct_register_funcs(srna, "rna_Panel_register", "rna_Panel_unregister", NULL);
RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT);
/* poll */
func = RNA_def_function(srna, "poll", NULL);
@@ -944,20 +973,20 @@ static void rna_def_panel(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", ""));
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* draw */
func = RNA_def_function(srna, "draw", NULL);
RNA_def_function_ui_description(func, "Draw UI elements into the panel UI layout");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
func = RNA_def_function(srna, "draw_header", NULL);
RNA_def_function_ui_description(func, "Draw UI elements into the panel's header UI layout");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "UILayout");
@@ -1039,6 +1068,7 @@ static void rna_def_uilist(BlenderRNA *brna)
RNA_def_struct_refine_func(srna, "rna_UIList_refine");
RNA_def_struct_register_funcs(srna, "rna_UIList_register", "rna_UIList_unregister", NULL);
RNA_def_struct_idprops_func(srna, "rna_UIList_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_PUBLIC_NAMESPACE_INHERIT);
/* Registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
@@ -1084,35 +1114,35 @@ static void rna_def_uilist(BlenderRNA *brna)
"function, you may want to check given 'item' is of the right type...)");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Layout to draw the item");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take Collection property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "item", "AnyType", "", "Item of the collection property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_int(func, "icon", 0, 0, INT_MAX, "", "Icon of the item in the collection", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "active_data", "AnyType", "",
"Data from which to take property for the active element");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "active_property", NULL, 0, "",
"Identifier of property in active_data, for the active element");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "index", 0, 0, INT_MAX, "", "Index of the item in the collection", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_PYFUNC_OPTIONAL);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_PYFUNC_OPTIONAL);
prop = RNA_def_property(func, "flt_flag", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(prop, "", "The filter-flag result for this item");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_PYFUNC_OPTIONAL);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_PYFUNC_OPTIONAL);
/* draw_filter */
func = RNA_def_function(srna, "draw_filter", NULL);
RNA_def_function_ui_description(func, "Draw filtering options");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Layout to draw the item");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* filter */
func = RNA_def_function(srna, "filter_items", NULL);
@@ -1120,19 +1150,19 @@ static void rna_def_uilist(BlenderRNA *brna)
"filter_flags, and reorder results in filter_neworder arrays)");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take Collection property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data, for the collection");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(func, "filter_flags", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_DYNAMIC);
+ RNA_def_property_flag(prop, PARM_REQUIRED | PROP_DYNAMIC);
RNA_def_property_array(prop, 1); /* XXX Dummy value, default 0 does not work */
RNA_def_property_ui_text(prop, "", "An array of filter flags, one for each item in the collection (NOTE: "
"FILTER_ITEM bit is reserved, it defines whether the item is shown or not)");
RNA_def_function_output(func, prop);
prop = RNA_def_property(func, "filter_neworder", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_DYNAMIC);
+ RNA_def_property_flag(prop, PARM_REQUIRED | PROP_DYNAMIC);
RNA_def_property_array(prop, 1); /* XXX Dummy value, default 0 does not work */
RNA_def_property_ui_text(prop, "", "An array of indices, one for each item in the collection, mapping the org "
"index to the new one");
@@ -1160,13 +1190,14 @@ static void rna_def_header(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "Header");
RNA_def_struct_refine_func(srna, "rna_Header_refine");
RNA_def_struct_register_funcs(srna, "rna_Header_register", "rna_Header_unregister", NULL);
+ RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT);
/* draw */
func = RNA_def_function(srna, "draw", NULL);
RNA_def_function_ui_description(func, "Draw UI elements into the header UI layout");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_define_verify_sdna(0); /* not in sdna */
@@ -1207,6 +1238,7 @@ static void rna_def_menu(BlenderRNA *brna)
RNA_def_struct_refine_func(srna, "rna_Menu_refine");
RNA_def_struct_register_funcs(srna, "rna_Menu_register", "rna_Menu_unregister", NULL);
RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT);
/* poll */
func = RNA_def_function(srna, "poll", NULL);
@@ -1214,14 +1246,14 @@ static void rna_def_menu(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", ""));
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* draw */
func = RNA_def_function(srna, "draw", NULL);
RNA_def_function_ui_description(func, "Draw UI elements into the menu UI layout");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_define_verify_sdna(false); /* not in sdna */
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 9d55115a14c..7d8d24670a7 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -397,7 +397,7 @@ static void api_ui_item_op(FunctionRNA *func)
{
PropertyRNA *parm;
parm = RNA_def_string(func, "operator", NULL, 0, "", "Identifier of the operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void api_ui_item_op_common(FunctionRNA *func)
@@ -411,9 +411,9 @@ static void api_ui_item_rna_common(FunctionRNA *func)
PropertyRNA *parm;
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_api_ui_layout(StructRNA *srna)
@@ -481,7 +481,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_return(func, parm);
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take the icon");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_function_ui_description(func, "Return the custom icon for this data, "
"use it e.g. to get materials or texture icons");
@@ -492,7 +492,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
parm = RNA_def_string(func, "identifier", NULL, 0, "", "Identifier of the enum item");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Return the UI name for this enum item");
func = RNA_def_function(srna, "enum_item_description", "rna_ui_get_enum_description");
@@ -501,7 +501,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
parm = RNA_def_string(func, "identifier", NULL, 0, "", "Identifier of the enum item");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Return the UI description for this enum item");
func = RNA_def_function(srna, "enum_item_icon", "rna_ui_get_enum_icon");
@@ -510,7 +510,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
parm = RNA_def_string(func, "identifier", NULL, 0, "", "Identifier of the enum item");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Return the icon for this enum item");
/* items */
@@ -541,15 +541,15 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "prop_enum", "rna_uiItemEnumR_string");
api_ui_item_rna_common(func);
parm = RNA_def_string(func, "value", NULL, 0, "", "Enum property value");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common(func);
func = RNA_def_function(srna, "prop_search", "rna_uiItemPointerR");
api_ui_item_rna_common(func);
parm = RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "search_property", NULL, 0, "", "Identifier of search collection property");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common(func);
func = RNA_def_function(srna, "operator", "rna_uiItemO");
@@ -557,23 +557,22 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, just the icon/text");
parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
- parm = RNA_def_pointer(func, "properties", "OperatorProperties", "",
- "Operator properties to fill in, return when 'properties' is set to true");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "Operator properties to fill in");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_function_return(func, parm);
RNA_def_function_ui_description(func, "Item. Places a button into the layout to call an Operator");
func = RNA_def_function(srna, "operator_enum", "uiItemsEnumO");
parm = RNA_def_string(func, "operator", NULL, 0, "", "Identifier of the operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "operator_menu_enum", "rna_uiItemMenuEnumO");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
api_ui_item_op(func); /* cant use api_ui_item_op_common because property must come right after */
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common(func);
/* useful in C but not in python */
@@ -582,39 +581,39 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "operator_enum_single", "uiItemEnumO_string");
api_ui_item_op_common(func);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "value", NULL, 0, "", "Enum property value");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "operator_boolean", "uiItemBooleanO");
api_ui_item_op_common(func);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "value", false, "", "Value of the property to call the operator with");
- RNA_def_property_flag(parm, PROP_REQUIRED); */
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); */
func = RNA_def_function(srna, "operator_int", "uiItemIntO");
api_ui_item_op_common(func);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "value", 0, INT_MIN, INT_MAX, "",
"Value of the property to call the operator with", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED); */
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); */
func = RNA_def_function(srna, "operator_float", "uiItemFloatO");
api_ui_item_op_common(func);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func, "value", 0, -FLT_MAX, FLT_MAX, "",
"Value of the property to call the operator with", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED); */
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); */
func = RNA_def_function(srna, "operator_string", "uiItemStringO");
api_ui_item_op_common(func);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "value", NULL, 0, "", "Value of the property to call the operator with");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
#endif
func = RNA_def_function(srna, "label", "rna_uiItemL");
@@ -627,7 +626,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "menu", NULL, 0, "", "Identifier of the menu");
api_ui_item_common(func);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
@@ -637,9 +636,9 @@ void RNA_api_ui_layout(StructRNA *srna)
/* context */
func = RNA_def_function(srna, "context_pointer_set", "uiLayoutSetContextPointer");
parm = RNA_def_string(func, "name", NULL, 0, "Name", "Name of entry in the context");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "data", "AnyType", "", "Pointer to put in context");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
/* templates */
func = RNA_def_function(srna, "template_header", "uiTemplateHeader");
@@ -664,35 +663,35 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_any_ID", "rna_uiTemplateAnyID");
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "type_property", NULL, 0, "",
"Identifier of property in data giving the type of the ID-blocks to use");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common_text(func);
func = RNA_def_function(srna, "template_path_builder", "rna_uiTemplatePathBuilder");
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "root", "ID", "", "ID-block from which path is evaluated from");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
api_ui_item_common_text(func);
func = RNA_def_function(srna, "template_modifier", "uiTemplateModifier");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Generates the UI layout for modifiers");
parm = RNA_def_pointer(func, "data", "Modifier", "", "Modifier data");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "template_constraint", "uiTemplateConstraint");
RNA_def_function_ui_description(func, "Generates the UI layout for constraints");
parm = RNA_def_pointer(func, "data", "Constraint", "", "Constraint data");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
RNA_def_function_return(func, parm);
@@ -700,7 +699,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lamps or worlds");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "id", "ID", "", "ID data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "show_buttons", true, "", "Show preview buttons?");
RNA_def_pointer(func, "parent", "ID", "", "ID data-block");
RNA_def_pointer(func, "slot", "TextureSlot", "", "Texture slot");
@@ -742,11 +741,11 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_layers", "uiTemplateLayers");
api_ui_item_rna_common(func);
parm = RNA_def_pointer(func, "used_layers_data", "AnyType", "", "Data from which to take property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "used_layers_property", NULL, 0, "", "Identifier of property in data");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "active_layer", 0, 0, INT_MAX, "Active Layer", "", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "template_color_picker", "uiTemplateColorPicker");
RNA_def_function_ui_description(func, "Item. A color wheel widget to pick colors");
@@ -764,34 +763,34 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_image_layers", "uiTemplateImageLayers");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "image", "Image", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "image_user", "ImageUser", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "template_image", "uiTemplateImage");
RNA_def_function_ui_description(func, "Item(s). User interface for selecting images and their source paths");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
parm = RNA_def_pointer(func, "image_user", "ImageUser", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_boolean(func, "compact", false, "", "Use more compact layout");
RNA_def_boolean(func, "multiview", false, "", "Expose Multi-View options");
func = RNA_def_function(srna, "template_image_settings", "uiTemplateImageSettings");
RNA_def_function_ui_description(func, "User interface for setting image format options");
parm = RNA_def_pointer(func, "image_settings", "ImageFormatSettings", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_boolean(func, "color_management", false, "", "Show color management settings");
func = RNA_def_function(srna, "template_image_stereo_3d", "uiTemplateImageStereo3d");
RNA_def_function_ui_description(func, "User interface for setting image stereo 3d options");
parm = RNA_def_pointer(func, "stereo_3d_format", "Stereo3dFormat", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "template_image_views", "uiTemplateImageViews");
RNA_def_function_ui_description(func, "User interface for setting image views output options");
parm = RNA_def_pointer(func, "image_settings", "ImageFormatSettings", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "template_movieclip", "uiTemplateMovieClip");
RNA_def_function_ui_description(func, "Item(s). User interface for selecting movie clips and their source paths");
@@ -807,22 +806,22 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func, "Item. A widget to control single marker settings.");
api_ui_item_rna_common(func);
parm = RNA_def_pointer(func, "clip_user", "MovieClipUser", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "track", "MovieTrackingTrack", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_boolean(func, "compact", false, "", "Use more compact layout");
func = RNA_def_function(srna, "template_movieclip_information", "uiTemplateMovieclipInformation");
RNA_def_function_ui_description(func, "Item. Movie clip information data.");
api_ui_item_rna_common(func);
parm = RNA_def_pointer(func, "clip_user", "MovieClipUser", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "template_list", "uiTemplateList");
RNA_def_function_ui_description(func, "Item. A list widget to display data, e.g. vertexgroups.");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "listtype_name", NULL, 0, "", "Identifier of the list type to use");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "list_id", NULL, 0, "",
"Identifier of this list widget (mandatory when using default \"" UI_UL_DEFAULT_CLASS_NAME
"\" class). "
@@ -831,15 +830,15 @@ void RNA_api_ui_layout(StructRNA *srna)
"class name is \"OBJECT_UL_vgroups\", and list_id is not set by the "
"script, then bl_idname = \"OBJECT_UL_vgroups\")");
parm = RNA_def_pointer(func, "dataptr", "AnyType", "", "Data from which to take the Collection property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "propname", NULL, 0, "", "Identifier of the Collection property in data");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "active_dataptr", "AnyType", "",
"Data from which to take the integer property, index of the active item");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "active_propname", NULL, 0, "",
"Identifier of the integer property in active_data, index of the active item");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_string(func, "item_dyntip_propname", NULL, 0, "",
"Identifier of a string property in items, to use as tooltip content");
RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Default and minimum number of rows to display", 0, INT_MAX);
@@ -866,34 +865,34 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_node_link", "uiTemplateNodeLink");
parm = RNA_def_pointer(func, "ntree", "NodeTree", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "node", "Node", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "template_node_view", "uiTemplateNodeView");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "ntree", "NodeTree", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "node", "Node", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "template_texture_user", "uiTemplateTextureUser");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
func = RNA_def_function(srna, "template_keymap_item_properties", "uiTemplateKeymapItemProperties");
parm = RNA_def_pointer(func, "item", "KeyMapItem", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "template_component_menu", "uiTemplateComponentMenu");
RNA_def_function_ui_description(func, "Item. Display expanded property in a popup menu");
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_string(func, "name", NULL, 0, "", "");
func = RNA_def_function(srna, "introspect", "uiLayoutIntrospect");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index ffdc5bb0592..b50cbee4885 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -138,23 +138,11 @@ static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
}
/* also used by buffer swap switching */
-static void rna_userdef_dpi_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_userdef_dpi_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
/* font's are stored at each DPI level, without this we can easy load 100's of fonts */
BLF_cache_clear();
- BKE_blender_userdef_refresh();
- WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
- WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
-}
-
-static void rna_userdef_virtual_pixel_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
-{
- /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
- BLF_cache_clear();
-
- BKE_blender_userdef_refresh();
-
/* force setting drawable again */
wmWindowManager *wm = bmain->wm.first;
if (wm) {
@@ -618,16 +606,17 @@ static void rna_AddonPref_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
RNA_struct_free_extension(type, &apt->ext);
+ RNA_struct_free(&BLENDER_RNA, type);
BKE_addon_pref_type_remove(apt);
- RNA_struct_free(&BLENDER_RNA, type);
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
}
-static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_AddonPref_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
bAddonPrefType *apt, dummyapt = {{'\0'}};
bAddon dummyaddon = {NULL};
@@ -650,10 +639,8 @@ static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void
/* check if we have registered this header type before, and remove it */
apt = BKE_addon_pref_type_find(dummyaddon.module, true);
- if (apt) {
- if (apt->ext.srna) {
- rna_AddonPref_unregister(bmain, apt->ext.srna);
- }
+ if (apt && apt->ext.srna) {
+ rna_AddonPref_unregister(bmain, apt->ext.srna);
}
/* create a new header type */
@@ -3168,6 +3155,7 @@ static void rna_def_userdef_addon_pref(BlenderRNA *brna)
RNA_def_struct_refine_func(srna, "rna_AddonPref_refine");
RNA_def_struct_register_funcs(srna, "rna_AddonPref_register", "rna_AddonPref_unregister", NULL);
RNA_def_struct_idprops_func(srna, "rna_AddonPref_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); /* Mandatory! */
/* registration */
RNA_define_verify_sdna(0);
@@ -3287,7 +3275,7 @@ static void rna_def_userdef_walk_navigation(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mouse_reverse", PROP_BOOLEAN, PROP_BOOLEAN);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_WALK_MOUSE_REVERSE);
- RNA_def_property_ui_text(prop, "Reverse Mouse", "Reverse the mouse look");
+ RNA_def_property_ui_text(prop, "Reverse Mouse", "Reverse the vertical movement of the mouse");
}
static void rna_def_userdef_view(BlenderRNA *brna)
@@ -3315,6 +3303,13 @@ static void rna_def_userdef_view(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem line_width[] = {
+ {-1, "THIN", 0, "Thin", "Thinner lines than the default"},
+ { 0, "AUTO", 0, "Auto", "Automatic line width based on UI scale"},
+ { 1, "THICK", 0, "Thick", "Thicker lines than the default"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
PropertyRNA *prop;
StructRNA *srna;
@@ -3325,6 +3320,18 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "View & Controls", "Preferences related to viewing data");
/* View */
+ prop = RNA_def_property(srna, "ui_scale", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_ui_text(prop, "UI Scale", "Changes the size of the fonts and buttons in the interface");
+ RNA_def_property_range(prop, 0.25f, 4.0f);
+ RNA_def_property_ui_range(prop, 0.5f, 2.0f, 1, 2);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
+
+ prop = RNA_def_property(srna, "ui_line_width", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, line_width);
+ RNA_def_property_ui_text(prop, "UI Line Width",
+ "Changes the thickness of lines and points in the interface");
+ RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
/* display */
prop = RNA_def_property(srna, "show_tooltips", PROP_BOOLEAN, PROP_NONE);
@@ -3450,6 +3457,11 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Cursor Depth",
"Use the depth under the mouse when placing the cursor");
+ prop = RNA_def_property(srna, "use_cursor_lock_adjust", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_LOCK_CURSOR_ADJUST);
+ RNA_def_property_ui_text(prop, "Cursor Lock Adjust",
+ "Place the cursor without 'jumping' to the new location (when lock-to-cursor is used)");
+
prop = RNA_def_property(srna, "use_camera_lock_parent", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag", USER_CAM_LOCK_NO_PARENT);
RNA_def_property_ui_text(prop, "Camera Parent Lock",
@@ -3916,12 +3928,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static EnumPropertyItem virtual_pixel_mode_items[] = {
- {VIRTUAL_PIXEL_NATIVE, "NATIVE", 0, "Native", "Use native pixel size of the display"},
- {VIRTUAL_PIXEL_DOUBLE, "DOUBLE", 0, "Double", "Use double the native pixel size of the display"},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "UserPreferencesSystem", NULL);
RNA_def_struct_sdna(srna, "UserDef");
RNA_def_struct_nested(brna, srna, "UserPreferences");
@@ -3936,21 +3942,19 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
prop = RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "dpi");
- RNA_def_property_range(prop, 48, 144);
- RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display");
- RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
-
- prop = RNA_def_property(srna, "virtual_pixel_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "virtual_pixel");
- RNA_def_property_enum_items(prop, virtual_pixel_mode_items);
- RNA_def_property_ui_text(prop, "Virtual Pixel Mode", "Modify the pixel size for hi-res devices");
- RNA_def_property_update(prop, 0, "rna_userdef_virtual_pixel_update");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "DPI",
+ "DPI for add-ons to use when drawing custom user interface elements, controlled by "
+ "operating system settings and Blender UI scale, with a reference value of 72 DPI "
+ "(note that since this value includes a user defined scale, it is not always the "
+ "actual monitor DPI)");
prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_sdna(prop, NULL, "pixelsize");
- RNA_def_property_ui_text(prop, "Pixel Size", "");
+ RNA_def_property_ui_text(prop, "Pixel Size",
+ "Suggested line thickness and point size in pixels, for add-ons drawing custom user "
+ "interface elements, controlled by operating system settings and Blender UI scale");
prop = RNA_def_property(srna, "font_path_ui", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_sdna(prop, NULL, "font_path_ui");
@@ -3998,11 +4002,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Translate New Names", "Translate new data names (when adding/creating some)");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "use_textured_fonts", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_USETEXTUREFONT);
- RNA_def_property_ui_text(prop, "Textured Fonts", "Use textures for drawing international fonts");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
/* System & OpenGL */
prop = RNA_def_property(srna, "solid_lights", PROP_COLLECTION, PROP_NONE);
@@ -4180,6 +4179,10 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Selection Method",
"Use OpenGL occlusion queries or selection render mode to accelerate selection");
+ prop = RNA_def_property(srna, "use_select_pick_depth", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpu_select_pick_deph", 1);
+ RNA_def_property_ui_text(prop, "OpenGL Depth Picking", "Use the depth buffer for picking 3D View selection");
+
/* Full scene anti-aliasing */
prop = RNA_def_property(srna, "multi_sample", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "ogl_multisamples");
@@ -4332,7 +4335,7 @@ static void rna_def_userdef_input(BlenderRNA *brna)
prop = RNA_def_property(srna, "ndof_deadzone", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Deadzone", "Deadzone of the 3D Mouse");
+ RNA_def_property_ui_text(prop, "Deadzone", "Threshold of initial movement needed from the device's rest position");
RNA_def_property_update(prop, 0, "rna_userdef_ndof_deadzone_update");
prop = RNA_def_property(srna, "ndof_pan_yz_swap_axis", PROP_BOOLEAN, PROP_NONE);
@@ -4612,8 +4615,8 @@ static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cpro
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove add-on");
parm = RNA_def_pointer(func, "addon", "Addon", "", "Add-on 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_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_userdef_autoexec_path_collection(BlenderRNA *brna, PropertyRNA *cprop)
@@ -4638,8 +4641,8 @@ static void rna_def_userdef_autoexec_path_collection(BlenderRNA *brna, PropertyR
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove path");
parm = RNA_def_pointer(func, "pathcmp", "PathCompare", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
void RNA_def_userdef(BlenderRNA *brna)
@@ -4674,6 +4677,11 @@ void RNA_def_userdef(BlenderRNA *brna)
"Active section of the user preferences shown in the user interface");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ /* don't expose this directly via the UI, modify via an operator */
+ prop = RNA_def_property(srna, "app_template", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "app_template");
+ RNA_def_property_ui_text(prop, "Application Template", "");
+
prop = RNA_def_property(srna, "themes", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "themes", NULL);
RNA_def_property_struct_type(prop, "Theme");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 35c9c9bcc89..df3eae4f221 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -32,6 +32,7 @@
#include "DNA_windowmanager_types.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -939,35 +940,8 @@ static void rna_wmClipboard_set(PointerRNA *UNUSED(ptr), const char *value)
}
#ifdef WITH_PYTHON
-static void rna_Operator_unregister(struct Main *bmain, StructRNA *type)
-{
- const char *idname;
- wmOperatorType *ot = RNA_struct_blender_type_get(type);
- wmWindowManager *wm;
-
- if (!ot)
- return;
-
- /* update while blender is running */
- wm = bmain->wm.first;
- if (wm) {
- WM_operator_stack_clear(wm);
-
- WM_operator_handlers_clear(wm, ot);
- }
- WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
-
- RNA_struct_free_extension(type, &ot->ext);
-
- idname = ot->idname;
- WM_operatortype_remove_ptr(ot);
- MEM_freeN((void *)idname);
- /* not to be confused with the RNA_struct_free that WM_operatortype_remove calls, they are 2 different srna's */
- RNA_struct_free(&BLENDER_RNA, type);
-}
-
-static int operator_poll(bContext *C, wmOperatorType *ot)
+static int rna_operator_poll_cb(bContext *C, wmOperatorType *ot)
{
extern FunctionRNA rna_Operator_poll_func;
@@ -992,7 +966,7 @@ static int operator_poll(bContext *C, wmOperatorType *ot)
return visible;
}
-static int operator_execute(bContext *C, wmOperator *op)
+static int rna_operator_execute_cb(bContext *C, wmOperator *op)
{
extern FunctionRNA rna_Operator_execute_func;
@@ -1018,7 +992,7 @@ static int operator_execute(bContext *C, wmOperator *op)
}
/* same as execute() but no return value */
-static bool operator_check(bContext *C, wmOperator *op)
+static bool rna_operator_check_cb(bContext *C, wmOperator *op)
{
extern FunctionRNA rna_Operator_check_func;
@@ -1043,7 +1017,7 @@ static bool operator_check(bContext *C, wmOperator *op)
return result;
}
-static int operator_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int rna_operator_invoke_cb(bContext *C, wmOperator *op, const wmEvent *event)
{
extern FunctionRNA rna_Operator_invoke_func;
@@ -1070,7 +1044,7 @@ static int operator_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
/* same as invoke */
-static int operator_modal(bContext *C, wmOperator *op, const wmEvent *event)
+static int rna_operator_modal_cb(bContext *C, wmOperator *op, const wmEvent *event)
{
extern FunctionRNA rna_Operator_modal_func;
@@ -1096,7 +1070,7 @@ static int operator_modal(bContext *C, wmOperator *op, const wmEvent *event)
return result;
}
-static void operator_draw(bContext *C, wmOperator *op)
+static void rna_operator_draw_cb(bContext *C, wmOperator *op)
{
extern FunctionRNA rna_Operator_draw_func;
@@ -1115,7 +1089,7 @@ static void operator_draw(bContext *C, wmOperator *op)
}
/* same as exec(), but call cancel */
-static void operator_cancel(bContext *C, wmOperator *op)
+static void rna_operator_cancel_cb(bContext *C, wmOperator *op)
{
extern FunctionRNA rna_Operator_cancel_func;
@@ -1133,112 +1107,84 @@ static void operator_cancel(bContext *C, wmOperator *op)
RNA_parameter_list_free(&list);
}
-void operator_wrapper(wmOperatorType *ot, void *userdata);
-void macro_wrapper(wmOperatorType *ot, void *userdata);
+static void rna_Operator_unregister(struct Main *bmain, StructRNA *type);
+
+/* bpy_operator_wrap.c */
+extern void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata);
+extern void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata);
-static char _operator_idname[OP_MAX_TYPENAME];
-static char _operator_name[OP_MAX_TYPENAME];
-static char _operator_descr[RNA_DYN_DESCR_MAX];
-static char _operator_ctxt[RNA_DYN_DESCR_MAX];
-static char _operator_undo_group[OP_MAX_TYPENAME];
-static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_Operator_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
wmOperatorType dummyot = {NULL};
wmOperator dummyop = {NULL};
PointerRNA dummyotr;
int have_function[7];
+ struct {
+ char idname[OP_MAX_TYPENAME];
+ char name[OP_MAX_TYPENAME];
+ char description[RNA_DYN_DESCR_MAX];
+ char translation_context[RNA_DYN_DESCR_MAX];
+ char undo_group[OP_MAX_TYPENAME];
+ } temp_buffers;
+
/* setup dummy operator & operator type to store static properties in */
dummyop.type = &dummyot;
- dummyot.idname = _operator_idname; /* only assigne the pointer, string is NULL'd */
- dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
- dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
- dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
- dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */
+ dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */
+ dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */
+ dummyot.description = temp_buffers.description; /* only assigne the pointer, string is NULL'd */
+ dummyot.translation_context = temp_buffers.translation_context; /* only assigne the pointer, string is NULL'd */
+ dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */
RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr);
/* clear in case they are left unset */
- _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0';
+ temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.description[0] = temp_buffers.undo_group[0] = '\0';
/* We have to set default op context! */
- strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ strcpy(temp_buffers.translation_context, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
/* validate the python class */
if (validate(&dummyotr, data, have_function) != 0)
return NULL;
- { /* convert foo.bar to FOO_OT_bar
- * allocate the description and the idname in 1 go */
-
- /* inconveniently long name sanity check */
- {
- char *ch = _operator_idname;
- int i;
- int dot = 0;
- for (i = 0; *ch; i++) {
- if ((*ch >= 'a' && *ch <= 'z') || (*ch >= '0' && *ch <= '9') || *ch == '_') {
- /* pass */
- }
- else if (*ch == '.') {
- dot++;
- }
- else {
- BKE_reportf(reports, RPT_ERROR,
- "Registering operator class: '%s', invalid bl_idname '%s', at position %d",
- identifier, _operator_idname, i);
- return NULL;
- }
+ /* check if we have registered this operator type before, and remove it */
+ {
+ wmOperatorType *ot = WM_operatortype_find(dummyot.idname, true);
+ if (ot && ot->ext.srna)
+ rna_Operator_unregister(bmain, ot->ext.srna);
+ }
- ch++;
- }
+ if (!WM_operator_py_idname_ok_or_report(reports, identifier, dummyot.idname)) {
+ return NULL;
+ }
- if (i > ((int)sizeof(dummyop.idname)) - 3) {
- BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', "
- "is too long, maximum length is %d", identifier, _operator_idname,
- (int)sizeof(dummyop.idname) - 3);
- return NULL;
- }
+ char idname_conv[sizeof(dummyop.idname)];
+ WM_operator_bl_idname(idname_conv, dummyot.idname); /* convert the idname from python */
- if (dot != 1) {
- BKE_reportf(reports, RPT_ERROR,
- "Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character",
- identifier, _operator_idname);
- return NULL;
- }
- }
- /* end sanity check */
-
- {
- int idlen = strlen(_operator_idname) + 4;
- int namelen = strlen(_operator_name) + 1;
- int desclen = strlen(_operator_descr) + 1;
- int ctxtlen = strlen(_operator_ctxt) + 1;
- int ugrouplen = strlen(_operator_undo_group) + 1;
- char *ch;
- /* 2 terminators and 3 to convert a.b -> A_OT_b */
- ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname");
- WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
- dummyot.idname = ch;
- ch += idlen;
- strcpy(ch, _operator_name);
- dummyot.name = ch;
- ch += namelen;
- strcpy(ch, _operator_descr);
- dummyot.description = ch;
- ch += desclen;
- strcpy(ch, _operator_ctxt);
- dummyot.translation_context = ch;
- ch += ctxtlen;
- strcpy(ch, _operator_undo_group);
- dummyot.undo_group = ch;
- }
+ if (!RNA_struct_available_or_report(reports, idname_conv)) {
+ return NULL;
}
- /* check if we have registered this operator type before, and remove it */
+ /* Convert foo.bar to FOO_OT_bar
+ * allocate all strings at once. */
{
- wmOperatorType *ot = WM_operatortype_find(dummyot.idname, true);
- if (ot && ot->ext.srna)
- rna_Operator_unregister(bmain, ot->ext.srna);
+ const char *strings[] = {
+ idname_conv,
+ temp_buffers.name,
+ temp_buffers.description,
+ temp_buffers.translation_context,
+ temp_buffers.undo_group,
+ };
+ char *strings_table[ARRAY_SIZE(strings)];
+ BLI_string_join_array_by_sep_char_with_tableN('\0', strings_table, strings, ARRAY_SIZE(strings));
+
+ dummyot.idname = strings_table[0]; /* allocated string stored here */
+ dummyot.name = strings_table[1];
+ dummyot.description = strings_table[2];
+ dummyot.translation_context = strings_table[3];
+ dummyot.undo_group = strings_table[4];
+ BLI_assert(ARRAY_SIZE(strings) == 5);
}
/* XXX, this doubles up with the operator name [#29666]
@@ -1252,14 +1198,14 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
dummyot.ext.call = call;
dummyot.ext.free = free;
- dummyot.pyop_poll = (have_function[0]) ? operator_poll : NULL;
- dummyot.exec = (have_function[1]) ? operator_execute : NULL;
- dummyot.check = (have_function[2]) ? operator_check : NULL;
- dummyot.invoke = (have_function[3]) ? operator_invoke : NULL;
- dummyot.modal = (have_function[4]) ? operator_modal : NULL;
- dummyot.ui = (have_function[5]) ? operator_draw : NULL;
- dummyot.cancel = (have_function[6]) ? operator_cancel : NULL;
- WM_operatortype_append_ptr(operator_wrapper, (void *)&dummyot);
+ dummyot.pyop_poll = (have_function[0]) ? rna_operator_poll_cb : NULL;
+ dummyot.exec = (have_function[1]) ? rna_operator_execute_cb : NULL;
+ dummyot.check = (have_function[2]) ? rna_operator_check_cb : NULL;
+ dummyot.invoke = (have_function[3]) ? rna_operator_invoke_cb : NULL;
+ dummyot.modal = (have_function[4]) ? rna_operator_modal_cb : NULL;
+ dummyot.ui = (have_function[5]) ? rna_operator_draw_cb : NULL;
+ dummyot.cancel = (have_function[6]) ? rna_operator_cancel_cb : NULL;
+ WM_operatortype_append_ptr(BPY_RNA_operator_wrapper, (void *)&dummyot);
/* update while blender is running */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
@@ -1267,64 +1213,76 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
return dummyot.ext.srna;
}
+static void rna_Operator_unregister(struct Main *bmain, StructRNA *type)
+{
+ const char *idname;
+ wmOperatorType *ot = RNA_struct_blender_type_get(type);
+ wmWindowManager *wm;
+
+ if (!ot)
+ return;
+
+ /* update while blender is running */
+ wm = bmain->wm.first;
+ if (wm) {
+ WM_operator_stack_clear(wm);
+
+ WM_operator_handlers_clear(wm, ot);
+ }
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ RNA_struct_free_extension(type, &ot->ext);
+
+ idname = ot->idname;
+ WM_operatortype_remove_ptr(ot);
+
+ /* not to be confused with the RNA_struct_free that WM_operatortype_remove calls, they are 2 different srna's */
+ RNA_struct_free(&BLENDER_RNA, type);
+
+ MEM_freeN((void *)idname);
+}
+
static void **rna_Operator_instance(PointerRNA *ptr)
{
wmOperator *op = ptr->data;
return &op->py_instance;
}
-static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_MacroOperator_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
wmOperatorType dummyot = {NULL};
wmOperator dummyop = {NULL};
PointerRNA dummyotr;
int have_function[4];
+ struct {
+ char idname[OP_MAX_TYPENAME];
+ char name[OP_MAX_TYPENAME];
+ char description[RNA_DYN_DESCR_MAX];
+ char translation_context[RNA_DYN_DESCR_MAX];
+ char undo_group[OP_MAX_TYPENAME];
+ } temp_buffers;
+
/* setup dummy operator & operator type to store static properties in */
dummyop.type = &dummyot;
- dummyot.idname = _operator_idname; /* only assigne the pointer, string is NULL'd */
- dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
- dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
- dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
- dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */
+ dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */
+ dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */
+ dummyot.description = temp_buffers.description; /* only assigne the pointer, string is NULL'd */
+ dummyot.translation_context = temp_buffers.translation_context; /* only assigne the pointer, string is NULL'd */
+ dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */
RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr);
/* clear in case they are left unset */
- _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0';
+ temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.description[0] = temp_buffers.undo_group[0] = '\0';
/* We have to set default op context! */
- strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ strcpy(temp_buffers.translation_context, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
/* validate the python class */
if (validate(&dummyotr, data, have_function) != 0)
return NULL;
- { /* convert foo.bar to FOO_OT_bar
- * allocate the description and the idname in 1 go */
- int idlen = strlen(_operator_idname) + 4;
- int namelen = strlen(_operator_name) + 1;
- int desclen = strlen(_operator_descr) + 1;
- int ctxtlen = strlen(_operator_ctxt) + 1;
- int ugrouplen = strlen(_operator_undo_group) + 1;
- char *ch;
- /* 2 terminators and 3 to convert a.b -> A_OT_b */
- ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname");
- WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
- dummyot.idname = ch;
- ch += idlen;
- strcpy(ch, _operator_name);
- dummyot.name = ch;
- ch += namelen;
- strcpy(ch, _operator_descr);
- dummyot.description = ch;
- ch += desclen;
- strcpy(ch, _operator_ctxt);
- dummyot.translation_context = ch;
- ch += ctxtlen;
- strcpy(ch, _operator_undo_group);
- dummyot.undo_group = ch;
- }
-
if (strlen(identifier) >= sizeof(dummyop.idname)) {
BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s' is too long, maximum length is %d",
identifier, (int)sizeof(dummyop.idname));
@@ -1338,6 +1296,38 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
rna_Operator_unregister(bmain, ot->ext.srna);
}
+ if (!WM_operator_py_idname_ok_or_report(reports, identifier, dummyot.idname)) {
+ return NULL;
+ }
+
+ char idname_conv[sizeof(dummyop.idname)];
+ WM_operator_bl_idname(idname_conv, dummyot.idname); /* convert the idname from python */
+
+ if (!RNA_struct_available_or_report(reports, idname_conv)) {
+ return NULL;
+ }
+
+ /* Convert foo.bar to FOO_OT_bar
+ * allocate all strings at once. */
+ {
+ const char *strings[] = {
+ idname_conv,
+ temp_buffers.name,
+ temp_buffers.description,
+ temp_buffers.translation_context,
+ temp_buffers.undo_group,
+ };
+ char *strings_table[ARRAY_SIZE(strings)];
+ BLI_string_join_array_by_sep_char_with_tableN('\0', strings_table, strings, ARRAY_SIZE(strings));
+
+ dummyot.idname = strings_table[0]; /* allocated string stored here */
+ dummyot.name = strings_table[1];
+ dummyot.description = strings_table[2];
+ dummyot.translation_context = strings_table[3];
+ dummyot.undo_group = strings_table[4];
+ BLI_assert(ARRAY_SIZE(strings) == 5);
+ }
+
/* XXX, this doubles up with the operator name [#29666]
* for now just remove from dir(bpy.types) */
@@ -1348,10 +1338,10 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
dummyot.ext.call = call;
dummyot.ext.free = free;
- dummyot.pyop_poll = (have_function[0]) ? operator_poll : NULL;
- dummyot.ui = (have_function[3]) ? operator_draw : NULL;
+ dummyot.pyop_poll = (have_function[0]) ? rna_operator_poll_cb : NULL;
+ dummyot.ui = (have_function[3]) ? rna_operator_draw_cb : NULL;
- WM_operatortype_append_macro_ptr(macro_wrapper, (void *)&dummyot);
+ WM_operatortype_append_macro_ptr(BPY_RNA_operator_macro_wrapper, (void *)&dummyot);
/* update while blender is running */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
@@ -1471,6 +1461,7 @@ static void rna_def_operator(BlenderRNA *brna)
RNA_def_struct_register_funcs(srna, "rna_Operator_register", "rna_Operator_unregister", "rna_Operator_instance");
#endif
RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT);
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1556,6 +1547,7 @@ static void rna_def_operator(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Operator Properties", "Input properties of an Operator");
RNA_def_struct_refine_func(srna, "rna_OperatorProperties_refine");
RNA_def_struct_idprops_func(srna, "rna_OperatorProperties_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
}
static void rna_def_macro_operator(BlenderRNA *brna)
@@ -1573,6 +1565,7 @@ static void rna_def_macro_operator(BlenderRNA *brna)
"rna_Operator_instance");
#endif
RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT);
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 8d0b704a402..677ea92aea1 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -87,6 +87,11 @@ static void rna_Operator_report(wmOperator *op, int type, const char *msg)
BKE_report(op->reports, type, msg);
}
+static int rna_Operator_is_repeat(wmOperator *op, bContext *C)
+{
+ return WM_operator_is_repeat(C, op);
+}
+
/* since event isn't needed... */
static void rna_Operator_enum_search_invoke(bContext *C, wmOperator *op)
{
@@ -340,11 +345,11 @@ static void rna_generic_op_invoke(FunctionRNA *func, int flag)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "operator", "Operator", "", "Operator to call");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
if (flag & WM_GEN_INVOKE_EVENT) {
parm = RNA_def_pointer(func, "event", "Event", "", "Event");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
if (flag & WM_GEN_INVOKE_SIZE) {
@@ -365,21 +370,21 @@ void RNA_api_window(StructRNA *srna)
func = RNA_def_function(srna, "cursor_warp", "WM_cursor_warp");
parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Set the cursor position");
func = RNA_def_function(srna, "cursor_set", "WM_cursor_set");
parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, rna_enum_window_cursor_items);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Set the cursor");
func = RNA_def_function(srna, "cursor_modal_set", "WM_cursor_modal_set");
parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, rna_enum_window_cursor_items);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Set the cursor, so the previous cursor can be restored");
RNA_def_function(srna, "cursor_modal_restore", "WM_cursor_modal_restore");
@@ -402,14 +407,14 @@ void RNA_api_wm(StructRNA *srna)
"(called by invoke() with self, just before returning {'RUNNING_MODAL'})");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "operator", "Operator", "", "Operator to call");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_return(func, RNA_def_boolean(func, "handle", 1, "", "Whether adding the handler was successful"));
func = RNA_def_function(srna, "event_timer_add", "rna_event_timer_add");
RNA_def_function_ui_description(func, "Add a timer to the given window, to generate periodic 'TIMER' events");
parm = RNA_def_property(func, "time_step", PROP_FLOAT, PROP_NONE);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_range(parm, 0.0, FLT_MAX);
RNA_def_property_ui_text(parm, "Time Step", "Interval in seconds between timer events");
RNA_def_pointer(func, "window", "Window", "", "Window to attach the timer to, or None");
@@ -419,22 +424,22 @@ void RNA_api_wm(StructRNA *srna)
func = RNA_def_function(srna, "event_timer_remove", "rna_event_timer_remove");
parm = RNA_def_pointer(func, "timer", "Timer", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* Progress bar interface */
func = RNA_def_function(srna, "progress_begin", "rna_progress_begin");
RNA_def_function_ui_description(func, "Start progress report");
parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(parm, "min", "any value in range [0,9999]");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "max", PROP_FLOAT, PROP_NONE);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_ui_text(parm, "max", "any value in range [min+1,9998]");
func = RNA_def_function(srna, "progress_update", "rna_progress_update");
RNA_def_function_ui_description(func, "Update the progress feedback");
parm = RNA_def_property(func, "value", PROP_FLOAT, PROP_NONE);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_ui_text(parm, "value", "Any value between min and max as set in progress_begin()");
func = RNA_def_function(srna, "progress_end", "rna_progress_end");
@@ -474,39 +479,39 @@ void RNA_api_wm(StructRNA *srna)
func = RNA_def_function(srna, "pupmenu_begin__internal", "rna_PupMenuBegin");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "title", NULL, 0, "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, rna_enum_icon_items);
/* return */
parm = RNA_def_pointer(func, "menu", "UIPopupMenu", "", "");
- RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
RNA_def_function_return(func, parm);
/* wrap UI_popup_menu_end */
func = RNA_def_function(srna, "pupmenu_end__internal", "rna_PupMenuEnd");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "menu", "UIPopupMenu", "", "");
- RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
/* wrap uiPieMenuBegin */
func = RNA_def_function(srna, "piemenu_begin__internal", "rna_PieMenuBegin");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "title", NULL, 0, "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, rna_enum_icon_items);
parm = RNA_def_pointer(func, "event", "Event", "", "");
- RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
/* return */
parm = RNA_def_pointer(func, "menu_pie", "UIPieMenu", "", "");
- RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
RNA_def_function_return(func, parm);
/* wrap uiPieMenuEnd */
func = RNA_def_function(srna, "piemenu_end__internal", "rna_PieMenuEnd");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "menu", "UIPieMenu", "", "");
- RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
}
void RNA_api_operator(StructRNA *srna)
@@ -517,10 +522,16 @@ void RNA_api_operator(StructRNA *srna)
/* utility, not for registering */
func = RNA_def_function(srna, "report", "rna_Operator_report");
parm = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* utility, not for registering */
+ func = RNA_def_function(srna, "is_repeat", "rna_Operator_is_repeat");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ /* return */
+ parm = RNA_def_boolean(func, "result", 0, "result", "");
+ RNA_def_function_return(func, parm);
/* Registration */
@@ -530,14 +541,14 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", ""));
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* exec */
func = RNA_def_function(srna, "execute", NULL);
RNA_def_function_ui_description(func, "Execute the operator");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* better name? */
parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
@@ -548,7 +559,7 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_function_ui_description(func, "Check the operator settings, return True to signal a change to redraw");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "result", ""); /* better name? */
RNA_def_function_return(func, parm);
@@ -558,9 +569,9 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_function_ui_description(func, "Invoke the operator");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "event", "Event", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* better name? */
parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
@@ -570,9 +581,9 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_function_ui_description(func, "Modal operator function");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "event", "Event", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* better name? */
parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
@@ -583,14 +594,14 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_function_ui_description(func, "Draw function for the operator");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* cancel */
func = RNA_def_function(srna, "cancel", NULL);
RNA_def_function_ui_description(func, "Called when the operator is canceled");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
}
void RNA_api_macro(StructRNA *srna)
@@ -601,9 +612,9 @@ void RNA_api_macro(StructRNA *srna)
/* utility, not for registering */
func = RNA_def_function(srna, "report", "rna_Operator_report");
parm = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* Registration */
@@ -614,14 +625,14 @@ void RNA_api_macro(StructRNA *srna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", ""));
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* draw */
func = RNA_def_function(srna, "draw", NULL);
RNA_def_function_ui_description(func, "Draw function for the operator");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
}
void RNA_api_keyconfig(StructRNA *UNUSED(srna))
@@ -646,7 +657,7 @@ void RNA_api_keymap(StructRNA *srna)
func = RNA_def_function(srna, "restore_item_to_default", "rna_keymap_restore_item_to_default");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
}
void RNA_api_keymapitem(StructRNA *srna)
@@ -656,7 +667,7 @@ void RNA_api_keymapitem(StructRNA *srna)
func = RNA_def_function(srna, "compare", "WM_keymap_item_compare");
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "Comparison result", "");
RNA_def_function_return(func, parm);
}
@@ -669,11 +680,11 @@ void RNA_api_keymapitems(StructRNA *srna)
func = RNA_def_function(srna, "new", "rna_KeyMap_item_new");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "idname", NULL, 0, "Operator Identifier", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_event_type_items, 0, "Type", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "value", rna_enum_event_value_items, 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "any", 0, "Any", "");
RNA_def_boolean(func, "shift", 0, "Shift", "");
RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
@@ -689,11 +700,11 @@ void RNA_api_keymapitems(StructRNA *srna)
func = RNA_def_function(srna, "new_modal", "rna_KeyMap_item_new_modal");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "propvalue", NULL, 0, "Property Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_event_type_items, 0, "Type", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "value", rna_enum_event_value_items, 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "any", 0, "Any", "");
RNA_def_boolean(func, "shift", 0, "Shift", "");
RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
@@ -706,12 +717,12 @@ void RNA_api_keymapitems(StructRNA *srna)
func = RNA_def_function(srna, "remove", "rna_KeyMap_item_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "from_id", "WM_keymap_item_find_id");
parm = RNA_def_property(func, "id", PROP_INT, PROP_NONE);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_ui_text(parm, "id", "ID of the item");
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
RNA_def_function_return(func, parm);
@@ -724,7 +735,7 @@ void RNA_api_keymaps(StructRNA *srna)
func = RNA_def_function(srna, "new", "rna_keymap_new"); /* add_keymap */
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_enum(func, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", "");
RNA_def_enum(func, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
RNA_def_boolean(func, "modal", 0, "Modal", "");
@@ -734,12 +745,12 @@ void RNA_api_keymaps(StructRNA *srna)
func = RNA_def_function(srna, "remove", "rna_KeyMap_remove"); /* remove_keymap */
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Removed key map");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "find", "rna_keymap_find"); /* find_keymap */
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_enum(func, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", "");
RNA_def_enum(func, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Corresponding key map");
@@ -747,7 +758,7 @@ void RNA_api_keymaps(StructRNA *srna)
func = RNA_def_function(srna, "find_modal", "rna_keymap_find_modal"); /* find_keymap_modal */
parm = RNA_def_string(func, "name", NULL, 0, "Operator Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Corresponding key map");
RNA_def_function_return(func, parm);
}
@@ -759,15 +770,15 @@ void RNA_api_keyconfigs(StructRNA *srna)
func = RNA_def_function(srna, "new", "WM_keyconfig_new_user"); /* add_keyconfig */
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Added key configuration");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_KeyConfig_remove"); /* remove_keyconfig */
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Removed key configuration");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
#endif
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index b8ebb375a48..ad2b862141c 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -93,6 +93,7 @@ set(SRC
intern/MOD_solidify.c
intern/MOD_subsurf.c
intern/MOD_surface.c
+ intern/MOD_surfacedeform.c
intern/MOD_triangulate.c
intern/MOD_util.c
intern/MOD_uvwarp.c
@@ -113,6 +114,10 @@ set(SRC
intern/MOD_weightvg_util.h
)
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
if(WITH_ALEMBIC)
add_definitions(-DWITH_ALEMBIC)
list(APPEND INC
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 4c881445893..bf121af2bd1 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -85,6 +85,7 @@ extern ModifierTypeInfo modifierType_DataTransfer;
extern ModifierTypeInfo modifierType_NormalEdit;
extern ModifierTypeInfo modifierType_CorrectiveSmooth;
extern ModifierTypeInfo modifierType_MeshSequenceCache;
+extern ModifierTypeInfo modifierType_SurfaceDeform;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 567505ea45d..f2f76f13883 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -64,13 +64,13 @@ static void initData(ModifierData *md)
static void copyData(ModifierData *md, ModifierData *target)
{
+#if 0
ArmatureModifierData *amd = (ArmatureModifierData *) md;
+#endif
ArmatureModifierData *tamd = (ArmatureModifierData *) target;
- tamd->object = amd->object;
- tamd->deformflag = amd->deformflag;
- tamd->multi = amd->multi;
- BLI_strncpy(tamd->defgrp_name, amd->defgrp_name, sizeof(tamd->defgrp_name));
+ modifier_copyData_generic(md, target);
+ tamd->prevCos = NULL;
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md))
@@ -96,7 +96,7 @@ static void foreachObjectLink(
{
ArmatureModifierData *amd = (ArmatureModifierData *) md;
- walk(userData, ob, &amd->object, IDWALK_NOP);
+ walk(userData, ob, &amd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index b049457e640..874ac34b613 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -50,6 +50,7 @@
#include "BKE_curve.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
+#include "BKE_mesh.h"
#include "MOD_util.h"
@@ -95,10 +96,10 @@ static void foreachObjectLink(
{
ArrayModifierData *amd = (ArrayModifierData *) md;
- walk(userData, ob, &amd->start_cap, IDWALK_NOP);
- walk(userData, ob, &amd->end_cap, IDWALK_NOP);
- walk(userData, ob, &amd->curve_ob, IDWALK_NOP);
- walk(userData, ob, &amd->offset_ob, IDWALK_NOP);
+ walk(userData, ob, &amd->start_cap, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->end_cap, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->curve_ob, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->offset_ob, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -137,7 +138,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
- struct Scene *scene,
+ struct Scene *UNUSED(scene),
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
@@ -149,33 +150,15 @@ static void updateDepsgraph(ModifierData *md,
DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap");
}
if (amd->curve_ob) {
+ struct Depsgraph *depsgraph = DEG_get_graph_from_handle(node);
DEG_add_object_relation(node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve");
- DEG_add_special_eval_flag(scene->depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
+ DEG_add_special_eval_flag(depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
}
if (amd->offset_ob != NULL) {
DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset");
}
}
-static float vertarray_size(const MVert *mvert, int numVerts, int axis)
-{
- int i;
- float min_co, max_co;
-
- /* if there are no vertices, width is 0 */
- if (numVerts == 0) return 0;
-
- /* find the minimum and maximum coordinates on the desired axis */
- min_co = max_co = mvert->co[axis];
- mvert++;
- for (i = 1; i < numVerts; ++i, ++mvert) {
- if (mvert->co[axis] < min_co) min_co = mvert->co[axis];
- if (mvert->co[axis] > max_co) max_co = mvert->co[axis];
- }
-
- return max_co - min_co;
-}
-
BLI_INLINE float sum_v3(const float v[3])
{
return v[0] + v[1] + v[2];
@@ -472,12 +455,22 @@ static DerivedMesh *arrayModifier_doArray(
unit_m4(offset);
src_mvert = dm->getVertArray(dm);
- if (amd->offset_type & MOD_ARR_OFF_CONST)
- add_v3_v3v3(offset[3], offset[3], amd->offset);
+ if (amd->offset_type & MOD_ARR_OFF_CONST) {
+ add_v3_v3(offset[3], amd->offset);
+ }
if (amd->offset_type & MOD_ARR_OFF_RELATIVE) {
- for (j = 0; j < 3; j++)
- offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, chunk_nverts, j);
+ float min[3], max[3];
+ const MVert *src_mv;
+
+ INIT_MINMAX(min, max);
+ for (src_mv = src_mvert, j = chunk_nverts; j--; src_mv++) {
+ minmax_v3v3_v3(min, max, src_mv->co);
+ }
+
+ for (j = 3; j--; ) {
+ offset[3][j] += amd->scale[j] * (max[j] - min[j]);
+ }
}
if (use_offset_ob) {
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index 5874029ae08..93dc0203f83 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -65,19 +65,11 @@ static void initData(ModifierData *md)
static void copyData(ModifierData *md, ModifierData *target)
{
+#if 0
BevelModifierData *bmd = (BevelModifierData *) md;
BevelModifierData *tbmd = (BevelModifierData *) target;
-
- tbmd->value = bmd->value;
- tbmd->res = bmd->res;
- tbmd->flags = bmd->flags;
- tbmd->val_flags = bmd->val_flags;
- tbmd->lim_flags = bmd->lim_flags;
- tbmd->e_flags = bmd->e_flags;
- tbmd->mat = bmd->mat;
- tbmd->profile = bmd->profile;
- tbmd->bevel_angle = bmd->bevel_angle;
- BLI_strncpy(tbmd->defgrp_name, bmd->defgrp_name, sizeof(tbmd->defgrp_name));
+#endif
+ modifier_copyData_generic(md, target);
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index da0f5aa3923..1140460161f 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -59,6 +59,7 @@
#include "BLI_alloca.h"
#include "BLI_math_geom.h"
#include "BKE_material.h"
+#include "BKE_global.h" /* only to check G.debug */
#include "MEM_guardedalloc.h"
#include "bmesh.h"
@@ -101,7 +102,7 @@ static void foreachObjectLink(
{
BooleanModifierData *bmd = (BooleanModifierData *) md;
- walk(userData, ob, &bmd->object, IDWALK_NOP);
+ walk(userData, ob, &bmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -224,6 +225,8 @@ static DerivedMesh *applyModifier_bmesh(
result = get_quick_derivedMesh(ob, dm, bmd->object, dm_other, bmd->operation);
if (result == NULL) {
+ const bool is_flip = (is_negative_m4(ob->obmat) != is_negative_m4(bmd->object->obmat));
+
BMesh *bm;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm, dm_other);
@@ -235,6 +238,16 @@ static DerivedMesh *applyModifier_bmesh(
&((struct BMeshCreateParams){.use_toolflags = false,}));
DM_to_bmesh_ex(dm_other, bm, true);
+
+ if (UNLIKELY(is_flip)) {
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+ BMIter iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_face_normal_flip_ex(bm, efa, cd_loop_mdisp_offset, true);
+ }
+ }
+
DM_to_bmesh_ex(dm, bm, true);
/* main bmesh intersection setup */
@@ -246,7 +259,7 @@ static DerivedMesh *applyModifier_bmesh(
looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__);
- BM_mesh_calc_tessellation(bm, looptris, &tottri);
+ BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri);
/* postpone this until after tessellating
* so we can use the original normals before the vertex are moved */
@@ -262,7 +275,6 @@ static DerivedMesh *applyModifier_bmesh(
invert_m4_m4(imat, ob->obmat);
mul_m4_m4m4(omat, imat, bmd->object->obmat);
-
BMVert *eve;
i = 0;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
@@ -275,8 +287,13 @@ static DerivedMesh *applyModifier_bmesh(
/* we need face normals because of 'BM_face_split_edgenet'
* we could calculate on the fly too (before calling split). */
{
- float nmat[4][4];
- invert_m4_m4(nmat, omat);
+ float nmat[3][3];
+ copy_m3_m4(nmat, omat);
+ invert_m3(nmat);
+
+ if (UNLIKELY(is_flip)) {
+ negate_m3(nmat);
+ }
const short ob_src_totcol = bmd->object->totcol;
short *material_remap = BLI_array_alloca(material_remap, ob_src_totcol ? ob_src_totcol : 1);
@@ -286,7 +303,7 @@ static DerivedMesh *applyModifier_bmesh(
BMFace *efa;
i = 0;
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- mul_transposed_mat3_m4_v3(nmat, efa->no);
+ mul_transposed_m3_v3(nmat, efa->no);
normalize_v3(efa->no);
BM_elem_flag_enable(efa, BM_FACE_TAG); /* temp tag to test which side split faces are from */
@@ -306,11 +323,17 @@ static DerivedMesh *applyModifier_bmesh(
* currently this is ok for 'BM_mesh_intersect' */
// BM_mesh_normals_update(bm);
- /* change for testing */
bool use_separate = false;
bool use_dissolve = true;
bool use_island_connect = true;
+ /* change for testing */
+ if (G.debug & G_DEBUG) {
+ use_separate = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0;
+ use_dissolve = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0;
+ use_island_connect = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0;
+ }
+
BM_mesh_intersect(
bm,
looptris, tottri,
@@ -319,6 +342,7 @@ static DerivedMesh *applyModifier_bmesh(
use_separate,
use_dissolve,
use_island_connect,
+ false,
bmd->operation,
bmd->double_threshold);
diff --git a/source/blender/modifiers/intern/MOD_boolean_util.c b/source/blender/modifiers/intern/MOD_boolean_util.c
index 061b1198f7e..49010664aa8 100644
--- a/source/blender/modifiers/intern/MOD_boolean_util.c
+++ b/source/blender/modifiers/intern/MOD_boolean_util.c
@@ -390,6 +390,9 @@ static void exporter_InitGeomArrays(ExportMeshData *export_data,
* the operand. Data for those layers will not be allocated or initialized.
*/
+ CustomData_merge(&dm_left->vertData, &dm->vertData, merge_mask, CD_DEFAULT, num_verts);
+ CustomData_merge(&dm_right->vertData, &dm->vertData, merge_mask, CD_DEFAULT, num_verts);
+
CustomData_merge(&dm_left->loopData, &dm->loopData, merge_mask, CD_DEFAULT, num_loops);
CustomData_merge(&dm_right->loopData, &dm->loopData, merge_mask, CD_DEFAULT, num_loops);
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index a364eef2974..56a274b9ac9 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -47,6 +47,8 @@
#include "BKE_particle.h"
#include "BKE_scene.h"
+
+
#ifdef _OPENMP
# include "BKE_mesh.h" /* BKE_MESH_OMP_LIMIT */
#endif
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 33e5b3615d9..ddcf1852dc6 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -102,7 +102,7 @@ static void foreachObjectLink(
{
CastModifierData *cmd = (CastModifierData *) md;
- walk(userData, ob, &cmd->object, IDWALK_NOP);
+ walk(userData, ob, &cmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -124,12 +124,13 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
+ Object *object,
struct DepsNodeHandle *node)
{
CastModifierData *cmd = (CastModifierData *)md;
if (cmd->object != NULL) {
DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
+ DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index d15a6fcb1c8..e8c39770a14 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -125,9 +125,15 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
if (clmd) {
/* Actual code uses get_collisionobjects */
+#ifdef WITH_LEGACY_DEPSGRAPH
dag_add_collision_relations(forest, scene, ob, obNode, clmd->coll_parms->group, ob->lay|scene->lay, eModifierType_Collision, NULL, true, "Cloth Collision");
-
dag_add_forcefield_relations(forest, scene, ob, obNode, clmd->sim_parms->effector_weights, true, 0, "Cloth Field");
+#else
+ (void)forest;
+ (void)scene;
+ (void)ob;
+ (void)obNode;
+#endif
}
}
@@ -228,11 +234,11 @@ static void foreachIDLink(ModifierData *md, Object *ob,
ClothModifierData *clmd = (ClothModifierData *) md;
if (clmd->coll_parms) {
- walk(userData, ob, (ID **)&clmd->coll_parms->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&clmd->coll_parms->group, IDWALK_CB_NOP);
}
if (clmd->sim_parms && clmd->sim_parms->effector_weights) {
- walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_CB_NOP);
}
}
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index e7ff0a90fbc..74e49dda074 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -40,7 +40,6 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-
#include "BKE_collision.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_global.h"
@@ -48,6 +47,8 @@
#include "BKE_pointcache.h"
#include "BKE_scene.h"
+#include "MOD_modifiertypes.h"
+
static void initData(ModifierData *md)
{
CollisionModifierData *collmd = (CollisionModifierData *) md;
@@ -152,8 +153,6 @@ static void deformVerts(ModifierData *md, Object *ob,
collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame
collmd->mvert_num = mvert_num;
-
- DM_ensure_looptri(dm);
collmd->tri_num = dm->getNumLoopTri(dm);
{
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index 9bc96e593fd..c9a910d769b 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -39,7 +39,6 @@
#include "BLI_utildefines.h"
-
#include "BKE_cdderivedmesh.h"
#include "BKE_lattice.h"
#include "BKE_library_query.h"
@@ -48,6 +47,7 @@
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
+#include "MOD_modifiertypes.h"
static void initData(ModifierData *md)
{
@@ -89,7 +89,7 @@ static void foreachObjectLink(
{
CurveModifierData *cmd = (CurveModifierData *) md;
- walk(userData, ob, &cmd->object, IDWALK_NOP);
+ walk(userData, ob, &cmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -111,7 +111,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
- struct Scene *scene,
+ struct Scene *UNUSED(scene),
Object *object,
struct DepsNodeHandle *node)
{
@@ -123,8 +123,9 @@ static void updateDepsgraph(ModifierData *md,
/* TODO(sergey): Currently path is evaluated as a part of modifier stack,
* might be changed in the future.
*/
+ struct Depsgraph *depsgraph = DEG_get_graph_from_handle(node);
DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier");
- DEG_add_special_eval_flag(scene->depsgraph, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH);
+ DEG_add_special_eval_flag(depsgraph, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH);
}
DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "Curve Modifier");
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index f5ab28d3d88..a2210893602 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -124,7 +124,7 @@ static void foreachObjectLink(
ObjectWalkFunc walk, void *userData)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
- walk(userData, ob, &dtmd->ob_source, IDWALK_NOP);
+ walk(userData, ob, &dtmd->ob_source, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -179,7 +179,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
/* Only used to check wehther we are operating on org data or not... */
Mesh *me = ob->data;
- MVert *mvert;
const bool invert_vgroup = (dtmd->flags & MOD_DATATRANSFER_INVERT_VGROUP) != 0;
@@ -192,8 +191,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
BLI_SPACE_TRANSFORM_SETUP(space_transform, ob, dtmd->ob_source);
}
- mvert = dm->getVertArray(dm);
- if ((me->mvert == mvert) && (dtmd->data_types & DT_TYPES_AFFECT_MESH)) {
+ MVert *mvert = dm->getVertArray(dm);
+ MEdge *medge = dm->getEdgeArray(dm);
+ if (((me->mvert == mvert) || (me->medge == medge)) && (dtmd->data_types & DT_TYPES_AFFECT_MESH)) {
/* We need to duplicate data here, otherwise setting custom normals, edges' shaprness, etc., could
* modify org mesh, see T43671. */
dm = CDDM_copy(dm);
@@ -211,6 +211,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
if (BKE_reports_contain(&reports, RPT_ERROR)) {
modifier_setError(md, "%s", BKE_reports_string(&reports, RPT_ERROR));
}
+ else if ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) {
+ modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' option in mesh settings");
+ }
else if (dm->getNumVerts(dm) > HIGH_POLY_WARNING || ((Mesh *)(dtmd->ob_source->data))->totvert > HIGH_POLY_WARNING) {
modifier_setError(md, "You are using a rather high poly as source or destination, computation might be slow");
}
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 059e096ddb4..fb8c0dd05a5 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -38,10 +38,12 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_image.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_texture.h"
@@ -73,14 +75,10 @@ static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
DisplaceModifierData *dmd = (DisplaceModifierData *) md;
-#endif
DisplaceModifierData *tdmd = (DisplaceModifierData *) target;
+#endif
modifier_copyData_generic(md, target);
-
- if (tdmd->texture) {
- id_us_plus(&tdmd->texture->id);
- }
}
static void freeData(ModifierData *md)
@@ -132,7 +130,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
{
DisplaceModifierData *dmd = (DisplaceModifierData *) md;
- walk(userData, ob, &dmd->map_object, IDWALK_NOP);
+ walk(userData, ob, &dmd->map_object, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -140,7 +138,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
DisplaceModifierData *dmd = (DisplaceModifierData *) md;
- walk(userData, ob, (ID **)&dmd->texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&dmd->texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
@@ -200,21 +198,130 @@ static void updateDepsgraph(ModifierData *md,
}
}
+typedef struct DisplaceUserdata {
+ /*const*/ DisplaceModifierData *dmd;
+ struct ImagePool *pool;
+ MDeformVert *dvert;
+ float weight;
+ int defgrp_index;
+ int direction;
+ bool use_global_direction;
+ float (*tex_co)[3];
+ float (*vertexCos)[3];
+ float local_mat[4][4];
+ MVert *mvert;
+ float (*vert_clnors)[3];
+} DisplaceUserdata;
+
+static void displaceModifier_do_task(void *userdata, const int iter)
+{
+ DisplaceUserdata *data = (DisplaceUserdata *)userdata;
+ DisplaceModifierData *dmd = data->dmd;
+ MDeformVert *dvert = data->dvert;
+ float weight = data->weight;
+ int defgrp_index = data->defgrp_index;
+ int direction = data->direction;
+ bool use_global_direction = data->use_global_direction;
+ float (*tex_co)[3] = data->tex_co;
+ float (*vertexCos)[3] = data->vertexCos;
+ MVert *mvert = data->mvert;
+ float (*vert_clnors)[3] = data->vert_clnors;
+
+ const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */
+
+ TexResult texres;
+ float strength = dmd->strength;
+ float delta;
+ float local_vec[3];
+
+ if (dvert) {
+ weight = defvert_find_weight(dvert + iter, defgrp_index);
+ if (weight == 0.0f) {
+ return;
+ }
+ }
+
+ if (dmd->texture) {
+ texres.nor = NULL;
+ BKE_texture_get_value_ex(dmd->modifier.scene, dmd->texture, tex_co[iter], &texres, data->pool, false);
+ delta = texres.tin - dmd->midlevel;
+ }
+ else {
+ delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */
+ }
+
+ if (dvert) {
+ strength *= weight;
+ }
+
+ delta *= strength;
+ CLAMP(delta, -10000, 10000);
+
+ switch (direction) {
+ case MOD_DISP_DIR_X:
+ if (use_global_direction) {
+ vertexCos[iter][0] += delta * data->local_mat[0][0];
+ vertexCos[iter][1] += delta * data->local_mat[1][0];
+ vertexCos[iter][2] += delta * data->local_mat[2][0];
+ }
+ else {
+ vertexCos[iter][0] += delta;
+ }
+ break;
+ case MOD_DISP_DIR_Y:
+ if (use_global_direction) {
+ vertexCos[iter][0] += delta * data->local_mat[0][1];
+ vertexCos[iter][1] += delta * data->local_mat[1][1];
+ vertexCos[iter][2] += delta * data->local_mat[2][1];
+ }
+ else {
+ vertexCos[iter][1] += delta;
+ }
+ break;
+ case MOD_DISP_DIR_Z:
+ if (use_global_direction) {
+ vertexCos[iter][0] += delta * data->local_mat[0][2];
+ vertexCos[iter][1] += delta * data->local_mat[1][2];
+ vertexCos[iter][2] += delta * data->local_mat[2][2];
+ }
+ else {
+ vertexCos[iter][2] += delta;
+ }
+ break;
+ case MOD_DISP_DIR_RGB_XYZ:
+ local_vec[0] = texres.tr - dmd->midlevel;
+ local_vec[1] = texres.tg - dmd->midlevel;
+ local_vec[2] = texres.tb - dmd->midlevel;
+ if (use_global_direction) {
+ mul_transposed_mat3_m4_v3(data->local_mat, local_vec);
+ }
+ mul_v3_fl(local_vec, strength);
+ add_v3_v3(vertexCos[iter], local_vec);
+ break;
+ case MOD_DISP_DIR_NOR:
+ vertexCos[iter][0] += delta * (mvert[iter].no[0] / 32767.0f);
+ vertexCos[iter][1] += delta * (mvert[iter].no[1] / 32767.0f);
+ vertexCos[iter][2] += delta * (mvert[iter].no[2] / 32767.0f);
+ break;
+ case MOD_DISP_DIR_CLNOR:
+ madd_v3_v3fl(vertexCos[iter], vert_clnors[iter], delta);
+ break;
+ }
+}
+
/* dm must be a CDDerivedMesh */
static void displaceModifier_do(
DisplaceModifierData *dmd, Object *ob,
DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
- int i;
MVert *mvert;
MDeformVert *dvert;
int direction = dmd->direction;
int defgrp_index;
float (*tex_co)[3];
float weight = 1.0f; /* init value unused but some compilers may complain */
- const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */
float (*vert_clnors)[3] = NULL;
- float local_mat[4][4];
+ float local_mat[4][4] = {{0}};
const bool use_global_direction = dmd->space == MOD_DISP_SPACE_GLOBAL;
if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return;
@@ -259,81 +366,26 @@ static void displaceModifier_do(
copy_m4_m4(local_mat, ob->obmat);
}
- for (i = 0; i < numVerts; i++) {
- TexResult texres;
- float strength = dmd->strength;
- float delta;
- float local_vec[3];
-
- if (dvert) {
- weight = defvert_find_weight(dvert + i, defgrp_index);
- if (weight == 0.0f) continue;
- }
-
- if (dmd->texture) {
- texres.nor = NULL;
- BKE_texture_get_value(dmd->modifier.scene, dmd->texture, tex_co[i], &texres, false);
- delta = texres.tin - dmd->midlevel;
- }
- else {
- delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */
- }
+ DisplaceUserdata data = {NULL};
+ data.dmd = dmd;
+ data.dvert = dvert;
+ data.weight = weight;
+ data.defgrp_index = defgrp_index;
+ data.direction = direction;
+ data.use_global_direction = use_global_direction;
+ data.tex_co = tex_co;
+ data.vertexCos = vertexCos;
+ copy_m4_m4(data.local_mat, local_mat);
+ data.mvert = mvert;
+ data.vert_clnors = vert_clnors;
+ if (dmd->texture != NULL) {
+ data.pool = BKE_image_pool_new();
+ BKE_texture_fetch_images_for_pool(dmd->texture, data.pool);
+ }
+ BLI_task_parallel_range(0, numVerts, &data, displaceModifier_do_task, numVerts > 512);
- if (dvert) strength *= weight;
-
- delta *= strength;
- CLAMP(delta, -10000, 10000);
-
- switch (direction) {
- case MOD_DISP_DIR_X:
- if (use_global_direction) {
- vertexCos[i][0] += delta * local_mat[0][0];
- vertexCos[i][1] += delta * local_mat[1][0];
- vertexCos[i][2] += delta * local_mat[2][0];
- }
- else {
- vertexCos[i][0] += delta;
- }
- break;
- case MOD_DISP_DIR_Y:
- if (use_global_direction) {
- vertexCos[i][0] += delta * local_mat[0][1];
- vertexCos[i][1] += delta * local_mat[1][1];
- vertexCos[i][2] += delta * local_mat[2][1];
- }
- else {
- vertexCos[i][1] += delta;
- }
- break;
- case MOD_DISP_DIR_Z:
- if (use_global_direction) {
- vertexCos[i][0] += delta * local_mat[0][2];
- vertexCos[i][1] += delta * local_mat[1][2];
- vertexCos[i][2] += delta * local_mat[2][2];
- }
- else {
- vertexCos[i][2] += delta;
- }
- break;
- case MOD_DISP_DIR_RGB_XYZ:
- local_vec[0] = texres.tr - dmd->midlevel;
- local_vec[1] = texres.tg - dmd->midlevel;
- local_vec[2] = texres.tb - dmd->midlevel;
- if (use_global_direction) {
- mul_transposed_mat3_m4_v3(local_mat, local_vec);
- }
- mul_v3_fl(local_vec, strength);
- add_v3_v3(vertexCos[i], local_vec);
- break;
- case MOD_DISP_DIR_NOR:
- vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f);
- vertexCos[i][1] += delta * (mvert[i].no[1] / 32767.0f);
- vertexCos[i][2] += delta * (mvert[i].no[2] / 32767.0f);
- break;
- case MOD_DISP_DIR_CLNOR:
- madd_v3_v3fl(vertexCos[i], vert_clnors[i], delta);
- break;
- }
+ if (data.pool != NULL) {
+ BKE_image_pool_free(data.pool);
}
if (tex_co) {
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index bde20e56748..eec97828091 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -36,12 +36,14 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_dynamicpaint.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
+#include "MOD_modifiertypes.h"
static void initData(ModifierData *md)
{
@@ -58,6 +60,15 @@ static void copyData(ModifierData *md, ModifierData *target)
DynamicPaintModifierData *tpmd = (DynamicPaintModifierData *)target;
dynamicPaint_Modifier_copy(pmd, tpmd);
+
+ if (tpmd->canvas) {
+ for (DynamicPaintSurface *surface = tpmd->canvas->surfaces.first; surface; surface = surface->next) {
+ id_us_plus((ID *)surface->init_texture);
+ }
+ }
+ if (tpmd->brush) {
+ id_us_plus((ID *)tpmd->brush->mat);
+ }
}
static void freeData(ModifierData *md)
@@ -116,7 +127,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
static bool is_brush_cb(Object *UNUSED(ob), ModifierData *pmd)
{
- return ((DynamicPaintModifierData*)pmd)->brush != NULL;
+ return ((DynamicPaintModifierData *)pmd)->brush != NULL;
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -129,6 +140,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
/* add relation from canvases to all brush objects */
if (pmd && pmd->canvas) {
+#ifdef WITH_LEGACY_DEPSGRAPH
for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
dag_add_forcefield_relations(forest, scene, ob, obNode, surface->effector_weights, true, 0, "Dynamic Paint Field");
@@ -137,6 +149,12 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
/* Actual code uses custom loop over group/scene without layer checks in dynamicPaint_doStep */
dag_add_collision_relations(forest, scene, ob, obNode, surface->brush_group, -1, eModifierType_DynamicPaint, is_brush_cb, false, "Dynamic Paint Brush");
}
+#else
+ (void)forest;
+ (void)scene;
+ (void)ob;
+ (void)obNode;
+#endif
}
}
@@ -174,15 +192,15 @@ static void foreachIDLink(ModifierData *md, Object *ob,
DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- walk(userData, ob, (ID **)&surface->brush_group, IDWALK_NOP);
- walk(userData, ob, (ID **)&surface->init_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&surface->brush_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&surface->init_texture, IDWALK_CB_USER);
if (surface->effector_weights) {
- walk(userData, ob, (ID **)&surface->effector_weights->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&surface->effector_weights->group, IDWALK_CB_NOP);
}
}
}
if (pmd->brush) {
- walk(userData, ob, (ID **)&pmd->brush->mat, IDWALK_USER);
+ walk(userData, ob, (ID **)&pmd->brush->mat, IDWALK_CB_USER);
}
}
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 4441edb299b..a17870f2bf4 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -48,6 +48,7 @@
#include "DNA_object_types.h"
+#include "MOD_modifiertypes.h"
static DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd)
{
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 38ffdaa709b..72bc046b440 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -51,9 +51,9 @@
#include "BKE_particle.h"
#include "BKE_scene.h"
-
#include "MEM_guardedalloc.h"
+#include "MOD_modifiertypes.h"
static void initData(ModifierData *md)
{
@@ -1001,8 +1001,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
ExplodeModifierData *emd = (ExplodeModifierData *) md;
ParticleSystemModifierData *psmd = findPrecedingParticlesystem(ob, md);
- DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
-
if (psmd) {
ParticleSystem *psys = psmd->psys;
@@ -1010,6 +1008,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (psys->part == NULL || psys->particles == NULL) return derivedData;
if (psmd->dm_final == NULL) return derivedData;
+ DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+
/* 1. find faces to be exploded if needed */
if (emd->facepa == NULL ||
psmd->flag & eParticleSystemFlag_Pars ||
diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c
index c202c5e1cb4..53f955b15f0 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim.c
@@ -47,6 +47,8 @@
#include "DEG_depsgraph_build.h"
#include "MOD_fluidsim_util.h"
+#include "MOD_modifiertypes.h"
+
#include "MEM_guardedalloc.h"
/* Fluidsim */
@@ -68,12 +70,13 @@ static void copyData(ModifierData *md, ModifierData *target)
FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
FluidsimModifierData *tfluidmd = (FluidsimModifierData *) target;
- if (tfluidmd->fss)
- MEM_freeN(tfluidmd->fss);
-
- tfluidmd->fss = MEM_dupallocN(fluidmd->fss);
- if (tfluidmd->fss && (tfluidmd->fss->meshVelocities != NULL)) {
- tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities);
+ fluidsim_free(tfluidmd);
+
+ if (fluidmd->fss) {
+ tfluidmd->fss = MEM_dupallocN(fluidmd->fss);
+ if (tfluidmd->fss && (tfluidmd->fss->meshVelocities != NULL)) {
+ tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities);
+ }
}
}
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
index ffbbb1b0745..3684e947fe0 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -78,8 +78,8 @@ void fluidsim_init(FluidsimModifierData *fluidmd)
fss->resolutionxyz = 65;
fss->previewresxyz = 45;
fss->realsize = 0.5;
- fss->guiDisplayMode = 2; // preview
- fss->renderDisplayMode = 3; // render
+ fss->guiDisplayMode = OB_FSDOM_PREVIEW;
+ fss->renderDisplayMode = OB_FSDOM_FINAL;
fss->viscosityValue = 1.0;
fss->viscosityExponent = 6;
@@ -98,7 +98,7 @@ void fluidsim_init(FluidsimModifierData *fluidmd)
/* fluid/inflow settings
* fss->iniVel --> automatically set to 0 */
- modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), "cache_fluid");
+ modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), OB_FLUIDSIM_SURF_DIR_DEFAULT);
/* first init of bounding box */
/* no bounding box needed */
@@ -150,9 +150,8 @@ void fluidsim_free(FluidsimModifierData *fluidmd)
if (fluidmd && fluidmd->fss) {
if (fluidmd->fss->meshVelocities) {
MEM_freeN(fluidmd->fss->meshVelocities);
- fluidmd->fss->meshVelocities = NULL;
}
- MEM_freeN(fluidmd->fss);
+ MEM_SAFE_FREE(fluidmd->fss);
}
return;
@@ -423,8 +422,6 @@ static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *
static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
{
- int displaymode = 0;
-
int curFrame = framenr /* - 1 */ /*scene->r.sfra*/; /* start with 0 at start frame */
/* why start with 0 as start frame?? Animations + time are frozen for frame 0 anyway. (See physics_fluid.c for that. - DG */
/* If we start with frame 0, we need to remap all animation channels, too, because they will all be 1 frame late if using frame-1! - DG */
@@ -435,25 +432,23 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
MPoly *mpoly;
MPoly mp_example = {0};
- if (!useRenderParams) {
- displaymode = fss->guiDisplayMode;
- }
- else {
- displaymode = fss->renderDisplayMode;
- }
+ const int displaymode = useRenderParams ? fss->renderDisplayMode : fss->guiDisplayMode;
switch (displaymode) {
- case 1:
+ case OB_FSDOM_GEOM:
/* just display original object */
return NULL;
- case 2:
+ case OB_FSDOM_PREVIEW:
/* use preview mesh */
BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
break;
- default: /* 3 */
- /* 3. use final mesh */
+ case OB_FSDOM_FINAL:
+ /* use final mesh */
BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
break;
+ default:
+ BLI_assert(!"Wrong fluidsim display type");
+ return NULL;
}
/* offset baked frame */
@@ -494,7 +489,7 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
/* load vertex velocities, if they exist...
* TODO? use generate flag as loading flag as well?
* warning, needs original .bobj.gz mesh loading filename */
- if (displaymode == 3) {
+ if (displaymode == OB_FSDOM_FINAL) {
fluidsim_read_vel_cache(fluidmd, dm, targetFile);
}
else {
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 9186b10d8ca..56c494ff3c0 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -115,7 +115,7 @@ static void foreachObjectLink(
{
HookModifierData *hmd = (HookModifierData *) md;
- walk(userData, ob, &hmd->object, IDWALK_NOP);
+ walk(userData, ob, &hmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index ce3fdc4bbe8..c2896e83a0b 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -29,7 +29,7 @@
*/
#include "BLI_utildefines.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -539,7 +539,7 @@ static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh
STACK_PUSH(index_anchors, i);
}
}
- DM_ensure_looptri(dm);
+
total_anchors = STACK_SIZE(index_anchors);
lmd->cache_system = initLaplacianSystem(numVerts, dm->getNumEdges(dm), dm->getNumLoopTri(dm),
total_anchors, lmd->anchor_grp_name, lmd->repeat);
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 7d4701e3ef2..dc246084dca 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -88,7 +88,7 @@ static void foreachObjectLink(
{
LatticeModifierData *lmd = (LatticeModifierData *) md;
- walk(userData, ob, &lmd->object, IDWALK_NOP);
+ walk(userData, ob, &lmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index 5e01a20d93b..18caf4a39f4 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -53,6 +53,8 @@
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
+#include "MOD_modifiertypes.h"
+
#include "BLI_strict_flags.h"
static void copyData(ModifierData *md, ModifierData *target)
@@ -74,7 +76,7 @@ static void foreachObjectLink(
ObjectWalkFunc walk, void *userData)
{
MaskModifierData *mmd = (MaskModifierData *)md;
- walk(userData, ob, &mmd->ob_arm, IDWALK_NOP);
+ walk(userData, ob, &mmd->ob_arm, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_meshcache_mdd.c b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
index 90fc750de3b..3dd3a5fc598 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_mdd.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
@@ -35,6 +35,9 @@
#ifdef __LITTLE_ENDIAN__
# include "BLI_endian_switch.h"
#endif
+#ifdef WIN32
+# include "BLI_winstuff.h"
+#endif
#include "MOD_meshcache_util.h" /* own include */
@@ -157,7 +160,7 @@ bool MOD_meshcache_read_mdd_index(FILE *fp,
return false;
}
- if (fseek(fp, index * mdd_head.verts_tot * sizeof(float) * 3, SEEK_CUR) != 0) {
+ if (fseek(fp, sizeof(float) * 3 * index * mdd_head.verts_tot, SEEK_CUR) != 0) {
*err_str = "Failed to seek frame";
return false;
}
diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
index 219eae4ecca..4b2b3f17d18 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
@@ -35,6 +35,10 @@
# include "BLI_endian_switch.h"
#endif
+#ifdef WIN32
+# include "BLI_winstuff.h"
+#endif
+
#include "MOD_meshcache_util.h" /* own include */
#include "DNA_modifier_types.h"
@@ -142,7 +146,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp,
return false;
}
- if (fseek(fp, index * pc2_head.verts_tot * sizeof(float) * 3, SEEK_CUR) != 0) {
+ if (fseek(fp, sizeof(float) * 3 * index * pc2_head.verts_tot, SEEK_CUR) != 0) {
*err_str = "Failed to seek frame";
return false;
}
diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.c b/source/blender/modifiers/intern/MOD_meshcache_util.c
index c263c4810e4..10861f5b02b 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_util.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_util.c
@@ -36,7 +36,7 @@ void MOD_meshcache_calc_range(const float frame, const char interp,
int r_index_range[2], float *r_factor)
{
if (interp == MOD_MESHCACHE_INTERP_NONE) {
- r_index_range[0] = r_index_range[1] = max_ii(0, min_ii(frame_tot - 1, iroundf(frame)));
+ r_index_range[0] = r_index_range[1] = max_ii(0, min_ii(frame_tot - 1, round_fl_to_int(frame)));
*r_factor = 1.0f; /* dummy */
}
else {
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 3f34319d25f..b1938395a7b 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -83,7 +83,7 @@ static void copyData(ModifierData *md, ModifierData *target)
MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
MeshDeformModifierData *tmmd = (MeshDeformModifierData *) target;
- *tmmd = *mmd;
+ modifier_copyData_generic(md, target);
if (mmd->bindinfluences) tmmd->bindinfluences = MEM_dupallocN(mmd->bindinfluences);
if (mmd->bindoffsets) tmmd->bindoffsets = MEM_dupallocN(mmd->bindoffsets);
@@ -91,8 +91,8 @@ static void copyData(ModifierData *md, ModifierData *target)
if (mmd->dyngrid) tmmd->dyngrid = MEM_dupallocN(mmd->dyngrid);
if (mmd->dyninfluences) tmmd->dyninfluences = MEM_dupallocN(mmd->dyninfluences);
if (mmd->dynverts) tmmd->dynverts = MEM_dupallocN(mmd->dynverts);
- if (mmd->bindweights) tmmd->dynverts = MEM_dupallocN(mmd->bindweights); /* deprecated */
- if (mmd->bindcos) tmmd->dynverts = MEM_dupallocN(mmd->bindcos); /* deprecated */
+ if (mmd->bindweights) tmmd->bindweights = MEM_dupallocN(mmd->bindweights); /* deprecated */
+ if (mmd->bindcos) tmmd->bindcos = MEM_dupallocN(mmd->bindcos); /* deprecated */
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
@@ -119,7 +119,7 @@ static void foreachObjectLink(
{
MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
- walk(userData, ob, &mmd->object, IDWALK_NOP);
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index 72644d56323..5b059ef89d2 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -25,12 +25,14 @@
*/
#include "DNA_cachefile_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BKE_cachefile.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -81,6 +83,7 @@ static void freeData(ModifierData *md)
#ifdef WITH_ALEMBIC
CacheReader_free(mcmd->reader);
#endif
+ mcmd->reader = NULL;
}
}
@@ -94,11 +97,15 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm,
- ModifierApplyFlag flag)
+ ModifierApplyFlag UNUSED(flag))
{
#ifdef WITH_ALEMBIC
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+ /* Only used to check whether we are operating on org data or not... */
+ Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
+ DerivedMesh *org_dm = dm;
+
Scene *scene = md->scene;
const float frame = BKE_scene_frame_get(scene);
const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS);
@@ -111,7 +118,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (!mcmd->reader) {
mcmd->reader = CacheReader_open_alembic_object(cache_file->handle,
- mcmd->reader,
+ NULL,
ob,
mcmd->object_path);
if (!mcmd->reader) {
@@ -120,6 +127,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
}
+ if (me != NULL) {
+ MVert *mvert = dm->getVertArray(dm);
+ MEdge *medge = dm->getEdgeArray(dm);
+ MPoly *mpoly = dm->getPolyArray(dm);
+ if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
+ /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
+ dm = CDDM_copy(dm);
+ }
+ }
+
DerivedMesh *result = ABC_read_mesh(mcmd->reader,
ob,
dm,
@@ -131,11 +148,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
modifier_setError(md, "%s", err_str);
}
+ if (!ELEM(result, NULL, dm) && (dm != org_dm)) {
+ dm->release(dm);
+ dm = org_dm;
+ }
+
return result ? result : dm;
- UNUSED_VARS(flag);
#else
return dm;
- UNUSED_VARS(md, ob, flag);
+ UNUSED_VARS(md, ob);
#endif
}
@@ -150,7 +171,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
- walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_USER);
+ walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_CB_USER);
}
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 88facb22e0e..157f37e973c 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -48,6 +48,8 @@
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
+#include "MOD_modifiertypes.h"
+
static void initData(ModifierData *md)
{
MirrorModifierData *mmd = (MirrorModifierData *) md;
@@ -72,7 +74,7 @@ static void foreachObjectLink(
{
MirrorModifierData *mmd = (MirrorModifierData *) md;
- walk(userData, ob, &mmd->mirror_ob, IDWALK_NOP);
+ walk(userData, ob, &mmd->mirror_ob, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -263,7 +265,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
/* handle uvs,
* let tessface recalc handle updating the MTFace data */
- if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) {
+ if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) || (is_zero_v2(mmd->uv_offset_copy) == false)) {
const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;
@@ -274,8 +276,10 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
int j = maxLoops;
dmloopuv += j; /* second set of loops only */
for (; j-- > 0; dmloopuv++) {
- if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0];
- if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1];
+ if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0];
+ if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1];
+ dmloopuv->uv[0] += mmd->uv_offset_copy[0];
+ dmloopuv->uv[1] += mmd->uv_offset_copy[1];
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index 90ad1bdfdc2..f9f17b88fa4 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -46,6 +46,8 @@
#include "BKE_modifier.h"
#include "BKE_subsurf.h"
+#include "MOD_modifiertypes.h"
+
static void initData(ModifierData *md)
{
MultiresModifierData *mmd = (MultiresModifierData *)md;
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 454c97451a8..20eae751ca4 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -501,7 +501,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
NormalEditModifierData *enmd = (NormalEditModifierData *) md;
- walk(userData, ob, &enmd->target, IDWALK_NOP);
+ walk(userData, ob, &enmd->target, IDWALK_CB_NOP);
}
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index e77cc655c16..8d8565e7e62 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -44,6 +44,8 @@
#include "BKE_modifier.h"
#include "BKE_ocean.h"
+#include "MOD_modifiertypes.h"
+
#ifdef WITH_OCEANSIM
static void init_cache_data(Object *ob, struct OceanModifierData *omd)
{
@@ -160,40 +162,19 @@ static void freeData(ModifierData *md)
static void copyData(ModifierData *md, ModifierData *target)
{
#ifdef WITH_OCEANSIM
+#if 0
OceanModifierData *omd = (OceanModifierData *) md;
+#endif
OceanModifierData *tomd = (OceanModifierData *) target;
- tomd->geometry_mode = omd->geometry_mode;
- tomd->resolution = omd->resolution;
- tomd->spatial_size = omd->spatial_size;
-
- tomd->wind_velocity = omd->wind_velocity;
+ freeData(target);
- tomd->damp = omd->damp;
- tomd->smallest_wave = omd->smallest_wave;
- tomd->depth = omd->depth;
-
- tomd->wave_alignment = omd->wave_alignment;
- tomd->wave_direction = omd->wave_direction;
- tomd->wave_scale = omd->wave_scale;
-
- tomd->chop_amount = omd->chop_amount;
- tomd->foam_coverage = omd->foam_coverage;
- tomd->time = omd->time;
-
- tomd->seed = omd->seed;
- tomd->flag = omd->flag;
+ modifier_copyData_generic(md, target);
tomd->refresh = 0;
- tomd->size = omd->size;
- tomd->repeat_x = omd->repeat_x;
- tomd->repeat_y = omd->repeat_y;
-
/* XXX todo: copy cache runtime too */
tomd->cached = 0;
- tomd->bakestart = omd->bakestart;
- tomd->bakeend = omd->bakeend;
tomd->oceancache = NULL;
tomd->ocean = BKE_ocean_add();
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 4e78e758dc3..0c91cb08da7 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -54,6 +54,8 @@
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
+#include "MOD_modifiertypes.h"
+
static void initData(ModifierData *md)
{
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
@@ -145,7 +147,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
{
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
- walk(userData, ob, &pimd->ob, IDWALK_NOP);
+ walk(userData, ob, &pimd->ob, IDWALK_CB_NOP);
}
static int particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p)
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index df94975e274..2c3d7f394bb 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -112,6 +112,56 @@ static void screwvert_iter_step(ScrewVertIter *iter)
}
}
+static DerivedMesh *dm_remove_doubles_on_axis(
+ DerivedMesh *result, MVert *mvert_new, const uint totvert, const uint step_tot,
+ const float axis_vec[3], const float axis_offset[3], const float merge_threshold)
+{
+ const float merge_threshold_sq = SQUARE(merge_threshold);
+ const bool use_offset = axis_offset != NULL;
+ uint tot_doubles = 0;
+ for (uint i = 0; i < totvert; i += 1) {
+ float axis_co[3];
+ if (use_offset) {
+ float offset_co[3];
+ sub_v3_v3v3(offset_co, mvert_new[i].co, axis_offset);
+ project_v3_v3v3_normalized(axis_co, offset_co, axis_vec);
+ add_v3_v3(axis_co, axis_offset);
+ }
+ else {
+ project_v3_v3v3_normalized(axis_co, mvert_new[i].co, axis_vec);
+ }
+ const float dist_sq = len_squared_v3v3(axis_co, mvert_new[i].co);
+ if (dist_sq <= merge_threshold_sq) {
+ mvert_new[i].flag |= ME_VERT_TMP_TAG;
+ tot_doubles += 1;
+ copy_v3_v3(mvert_new[i].co, axis_co);
+ }
+ }
+
+ if (tot_doubles != 0) {
+ uint tot = totvert * step_tot;
+ int *full_doubles_map = MEM_mallocN(sizeof(int) * tot, __func__);
+ copy_vn_i(full_doubles_map, (int)tot, -1);
+
+ uint tot_doubles_left = tot_doubles;
+ for (uint i = 0; i < totvert; i += 1) {
+ if (mvert_new[i].flag & ME_VERT_TMP_TAG) {
+ int *doubles_map = &full_doubles_map[totvert + i] ;
+ for (uint step = 1; step < step_tot; step += 1) {
+ *doubles_map = (int)i;
+ doubles_map += totvert;
+ }
+ tot_doubles_left -= 1;
+ if (tot_doubles_left == 0) {
+ break;
+ }
+ }
+ }
+ result = CDDM_merge_verts(result, full_doubles_map, (int)(tot_doubles * (step_tot - 1)), CDDM_MERGE_VERTS_DUMP_IF_MAPPED);
+ MEM_freeN(full_doubles_map);
+ }
+ return result;
+}
static void initData(ModifierData *md)
{
@@ -123,6 +173,7 @@ static void initData(ModifierData *md)
ltmd->steps = 16;
ltmd->render_steps = 16;
ltmd->iter = 1;
+ ltmd->merge_dist = 0.01f;
}
static void copyData(ModifierData *md, ModifierData *target)
@@ -798,13 +849,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (ltmd->ob_axis) {
axis_angle_normalized_to_mat3(mat3, axis_vec, step_angle);
- copy_m4_m3(mat, mat3);
}
else {
- unit_m4(mat);
- rotate_m4(mat, axis_char, step_angle);
- copy_m3_m4(mat3, mat);
+ axis_angle_to_mat3_single(mat3, axis_char, step_angle);
}
+ copy_m4_m3(mat, mat3);
if (screw_ofs)
madd_v3_v3fl(mat[3], axis_vec, screw_ofs * ((float)step / (float)(step_tot - 1)));
@@ -1052,6 +1101,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
MEM_freeN(vert_loop_map);
}
+ if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) {
+ DerivedMesh *result_prev = result;
+ result = dm_remove_doubles_on_axis(
+ result, mvert_new, totvert, step_tot,
+ axis_vec, ltmd->ob_axis ? mtx_tx[3] : NULL, ltmd->merge_dist);
+ if (result != result_prev) {
+ result->dirty |= DM_DIRTY_NORMALS;
+ }
+ }
+
if ((ltmd->flag & MOD_SCREW_NORMAL_CALC) == 0) {
result->dirty |= DM_DIRTY_NORMALS;
}
@@ -1095,7 +1154,7 @@ static void foreachObjectLink(
{
ScrewModifierData *ltmd = (ScrewModifierData *) md;
- walk(userData, ob, &ltmd->ob_axis, IDWALK_NOP);
+ walk(userData, ob, &ltmd->ob_axis, IDWALK_CB_NOP);
}
ModifierTypeInfo modifierType_Screw = {
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index 633311c2b87..a14747bc153 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -101,8 +101,8 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md;
- walk(userData, ob, &smd->target, IDWALK_NOP);
- walk(userData, ob, &smd->auxTarget, IDWALK_NOP);
+ walk(userData, ob, &smd->target, IDWALK_CB_NOP);
+ walk(userData, ob, &smd->auxTarget, IDWALK_CB_NOP);
}
static void deformVerts(ModifierData *md, Object *ob,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index c68f2651191..379eaea5b0c 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -290,7 +290,7 @@ static void foreachObjectLink(
ObjectWalkFunc walk, void *userData)
{
SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
- walk(userData, ob, &smd->origin, IDWALK_NOP);
+ walk(userData, ob, &smd->origin, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 8ed623734be..ad1e4badd3e 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -77,6 +77,8 @@
#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
+#include "MOD_modifiertypes.h"
+
#include "bmesh.h"
typedef struct {
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c
index f04d7432a8f..7f2d9e42fe6 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -45,7 +45,6 @@
#include "BLI_utildefines.h"
-
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -56,6 +55,8 @@
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
+#include "MOD_modifiertypes.h"
+
static void initData(ModifierData *md)
{
SmokeModifierData *smd = (SmokeModifierData *) md;
@@ -138,10 +139,16 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
/* Actual code uses get_collisionobjects */
+#ifdef WITH_LEGACY_DEPSGRAPH
dag_add_collision_relations(forest, scene, ob, obNode, smd->domain->fluid_group, ob->lay|scene->lay, eModifierType_Smoke, is_flow_cb, true, "Smoke Flow");
dag_add_collision_relations(forest, scene, ob, obNode, smd->domain->coll_group, ob->lay|scene->lay, eModifierType_Smoke, is_coll_cb, true, "Smoke Coll");
-
dag_add_forcefield_relations(forest, scene, ob, obNode, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field");
+#else
+ (void)forest;
+ (void)scene;
+ (void)ob;
+ (void)obNode;
+#endif
}
}
@@ -168,17 +175,17 @@ static void foreachIDLink(ModifierData *md, Object *ob,
SmokeModifierData *smd = (SmokeModifierData *) md;
if (smd->type == MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
- walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_NOP);
- walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_NOP);
- walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_CB_NOP);
if (smd->domain->effector_weights) {
- walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_CB_NOP);
}
}
if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) {
- walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_CB_USER);
}
}
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index 17adc7f1520..a0bbe5da04a 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -67,10 +67,17 @@ static void updateDepgraph(ModifierData *UNUSED(md), DagForest *forest,
Scene *scene, Object *ob, DagNode *obNode)
{
if (ob->soft) {
+#ifdef WITH_LEGACY_DEPSGRAPH
/* Actual code uses ccd_build_deflector_hash */
dag_add_collision_relations(forest, scene, ob, obNode, ob->soft->collision_group, ob->lay, eModifierType_Collision, NULL, false, "Softbody Collision");
dag_add_forcefield_relations(forest, scene, ob, obNode, ob->soft->effector_weights, true, 0, "Softbody Field");
+#else
+ (void)forest;
+ (void)scene;
+ (void)ob;
+ (void)obNode;
+#endif
}
}
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 911b6997058..e96771e0665 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -36,7 +36,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_stackdefines.h"
+#include "BLI_utildefines_stack.h"
#include "BLI_bitmap.h"
#include "BLI_math.h"
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 68987a1d28e..e5b0f9c0001 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -172,6 +172,7 @@ ModifierTypeInfo modifierType_Surface = {
/* structSize */ sizeof(SurfaceModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_AcceptsCVs |
eModifierTypeFlag_NoUserAdd,
/* copyData */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
new file mode 100644
index 00000000000..b692137b604
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -0,0 +1,1231 @@
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_math.h"
+#include "BLI_math_geom.h"
+#include "BLI_task.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
+#include "BKE_library_query.h"
+#include "BKE_modifier.h"
+
+#include "depsgraph_private.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_util.h"
+
+typedef struct SDefAdjacency {
+ struct SDefAdjacency *next;
+ unsigned int index;
+} SDefAdjacency;
+
+typedef struct SDefAdjacencyArray {
+ SDefAdjacency *first;
+ unsigned int num; /* Careful, this is twice the number of polygons (avoids an extra loop) */
+} SDefAdjacencyArray;
+
+typedef struct SDefEdgePolys {
+ unsigned int polys[2], num;
+} SDefEdgePolys;
+
+typedef struct SDefBindCalcData {
+ BVHTreeFromMesh * const treeData;
+ const SDefAdjacencyArray * const vert_edges;
+ const SDefEdgePolys * const edge_polys;
+ SDefVert * const bind_verts;
+ const MLoopTri * const looptri;
+ const MPoly * const mpoly;
+ const MEdge * const medge;
+ const MLoop * const mloop;
+ float (* const targetCos)[3];
+ float (* const vertexCos)[3];
+ float imat[4][4];
+ const float falloff;
+ int success;
+} SDefBindCalcData;
+
+typedef struct SDefBindPoly {
+ float (*coords)[3];
+ float (*coords_v2)[2];
+ float point_v2[2];
+ float weight_angular;
+ float weight_dist_proj;
+ float weight_dist;
+ float weight;
+ float scales[2];
+ float centroid[3];
+ float centroid_v2[2];
+ float normal[3];
+ float cent_edgemid_vecs_v2[2][2];
+ float edgemid_angle;
+ float point_edgemid_angles[2];
+ float corner_edgemid_angles[2];
+ float dominant_angle_weight;
+ unsigned int index;
+ unsigned int numverts;
+ unsigned int loopstart;
+ unsigned int edge_inds[2];
+ unsigned int edge_vert_inds[2];
+ unsigned int corner_ind;
+ unsigned int dominant_edge;
+ bool inside;
+} SDefBindPoly;
+
+typedef struct SDefBindWeightData {
+ SDefBindPoly *bind_polys;
+ unsigned int numpoly;
+ unsigned int numbinds;
+} SDefBindWeightData;
+
+typedef struct SDefDeformData {
+ const SDefVert * const bind_verts;
+ float (* const targetCos)[3];
+ float (* const vertexCos)[3];
+} SDefDeformData;
+
+/* Bind result values */
+enum {
+ MOD_SDEF_BIND_RESULT_SUCCESS = 1,
+ MOD_SDEF_BIND_RESULT_GENERIC_ERR = 0,
+ MOD_SDEF_BIND_RESULT_MEM_ERR = -1,
+ MOD_SDEF_BIND_RESULT_NONMANY_ERR = -2,
+ MOD_SDEF_BIND_RESULT_CONCAVE_ERR = -3,
+ MOD_SDEF_BIND_RESULT_OVERLAP_ERR = -4,
+};
+
+/* Infinite weight flags */
+enum {
+ MOD_SDEF_INFINITE_WEIGHT_ANGULAR = (1 << 0),
+ MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ = (1 << 1),
+ MOD_SDEF_INFINITE_WEIGHT_DIST = (1 << 2),
+};
+
+static void initData(ModifierData *md)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ smd->target = NULL;
+ smd->verts = NULL;
+ smd->flags = 0;
+ smd->falloff = 4.0f;
+}
+
+static void freeData(ModifierData *md)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+
+ if (smd->verts) {
+ for (int i = 0; i < smd->numverts; i++) {
+ if (smd->verts[i].binds) {
+ for (int j = 0; j < smd->verts[i].numbinds; j++) {
+ MEM_SAFE_FREE(smd->verts[i].binds[j].vert_inds);
+ MEM_SAFE_FREE(smd->verts[i].binds[j].vert_weights);
+ }
+
+ MEM_freeN(smd->verts[i].binds);
+ }
+ }
+
+ MEM_freeN(smd->verts);
+ smd->verts = NULL;
+ }
+}
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ SurfaceDeformModifierData *tsmd = (SurfaceDeformModifierData *)target;
+
+ freeData(target);
+
+ modifier_copyData_generic(md, target);
+
+ if (smd->verts) {
+ tsmd->verts = MEM_dupallocN(smd->verts);
+
+ for (int i = 0; i < smd->numverts; i++) {
+ if (smd->verts[i].binds) {
+ tsmd->verts[i].binds = MEM_dupallocN(smd->verts[i].binds);
+
+ for (int j = 0; j < smd->verts[i].numbinds; j++) {
+ if (smd->verts[i].binds[j].vert_inds) {
+ tsmd->verts[i].binds[j].vert_inds = MEM_dupallocN(smd->verts[i].binds[j].vert_inds);
+ }
+
+ if (smd->verts[i].binds[j].vert_weights) {
+ tsmd->verts[i].binds[j].vert_weights = MEM_dupallocN(smd->verts[i].binds[j].vert_weights);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+
+ walk(userData, ob, &smd->target, IDWALK_NOP);
+}
+
+static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ DagNode *obNode)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+
+ if (smd->target) {
+ DagNode *curNode = dag_get_node(forest, smd->target);
+
+ dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA, "Surface Deform Modifier");
+ }
+}
+
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ if (smd->target != NULL) {
+ DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "Surface Deform Modifier");
+ }
+}
+
+static void freeAdjacencyMap(SDefAdjacencyArray * const vert_edges, SDefAdjacency * const adj_ref, SDefEdgePolys * const edge_polys)
+{
+ MEM_freeN(edge_polys);
+
+ MEM_freeN(adj_ref);
+
+ MEM_freeN(vert_edges);
+}
+
+static int buildAdjacencyMap(const MPoly *poly, const MEdge *edge, const MLoop * const mloop, const unsigned int numpoly, const unsigned int numedges,
+ SDefAdjacencyArray * const vert_edges, SDefAdjacency *adj, SDefEdgePolys * const edge_polys)
+{
+ const MLoop *loop;
+
+ /* Fing polygons adjacent to edges */
+ for (int i = 0; i < numpoly; i++, poly++) {
+ loop = &mloop[poly->loopstart];
+
+ for (int j = 0; j < poly->totloop; j++, loop++) {
+ if (edge_polys[loop->e].num == 0) {
+ edge_polys[loop->e].polys[0] = i;
+ edge_polys[loop->e].polys[1] = -1;
+ edge_polys[loop->e].num++;
+ }
+ else if (edge_polys[loop->e].num == 1) {
+ edge_polys[loop->e].polys[1] = i;
+ edge_polys[loop->e].num++;
+ }
+ else {
+ return MOD_SDEF_BIND_RESULT_NONMANY_ERR;
+ }
+ }
+ }
+
+ /* Find edges adjacent to vertices */
+ for (int i = 0; i < numedges; i++, edge++) {
+ adj->next = vert_edges[edge->v1].first;
+ adj->index = i;
+ vert_edges[edge->v1].first = adj;
+ vert_edges[edge->v1].num += edge_polys[i].num;
+ adj++;
+
+ adj->next = vert_edges[edge->v2].first;
+ adj->index = i;
+ vert_edges[edge->v2].first = adj;
+ vert_edges[edge->v2].num += edge_polys[i].num;
+ adj++;
+ }
+
+ return MOD_SDEF_BIND_RESULT_SUCCESS;
+}
+
+BLI_INLINE void sortPolyVertsEdge(unsigned int *indices, const MLoop * const mloop, const unsigned int edge, const unsigned int num)
+{
+ bool found = false;
+
+ for (int i = 0; i < num; i++) {
+ if (mloop[i].e == edge) {
+ found = true;
+ }
+ if (found) {
+ *indices = mloop[i].v;
+ indices++;
+ }
+ }
+
+ /* Fill in remaining vertex indices that occur before the edge */
+ for (int i = 0; mloop[i].e != edge; i++) {
+ *indices = mloop[i].v;
+ indices++;
+ }
+}
+
+BLI_INLINE void sortPolyVertsTri(unsigned int *indices, const MLoop * const mloop, const unsigned int loopstart, const unsigned int num)
+{
+ for (int i = loopstart; i < num; i++) {
+ *indices = mloop[i].v;
+ indices++;
+ }
+
+ for (int i = 0; i < loopstart; i++) {
+ *indices = mloop[i].v;
+ indices++;
+ }
+}
+
+BLI_INLINE unsigned int nearestVert(SDefBindCalcData * const data, const float point_co[3])
+{
+ BVHTreeNearest nearest = {.dist_sq = FLT_MAX, .index = -1};
+ const MPoly *poly;
+ const MEdge *edge;
+ const MLoop *loop;
+ float t_point[3];
+ float max_dist = FLT_MAX;
+ float dist;
+ unsigned int index = 0;
+
+ mul_v3_m4v3(t_point, data->imat, point_co);
+
+ BLI_bvhtree_find_nearest(data->treeData->tree, t_point, &nearest, data->treeData->nearest_callback, data->treeData);
+
+ poly = &data->mpoly[data->looptri[nearest.index].poly];
+ loop = &data->mloop[poly->loopstart];
+
+ for (int i = 0; i < poly->totloop; i++, loop++) {
+ edge = &data->medge[loop->e];
+ dist = dist_squared_to_line_segment_v3(point_co, data->targetCos[edge->v1], data->targetCos[edge->v2]);
+
+ if (dist < max_dist) {
+ max_dist = dist;
+ index = loop->e;
+ }
+ }
+
+ edge = &data->medge[index];
+ if (len_squared_v3v3(point_co, data->targetCos[edge->v1]) < len_squared_v3v3(point_co, data->targetCos[edge->v2])) {
+ return edge->v1;
+ }
+ else {
+ return edge->v2;
+ }
+}
+
+BLI_INLINE int isPolyValid(const float coords[][2], const unsigned int nr)
+{
+ float prev_co[2];
+ float curr_vec[2], prev_vec[2];
+
+ if (!is_poly_convex_v2(coords, nr)) {
+ return MOD_SDEF_BIND_RESULT_CONCAVE_ERR;
+ }
+
+ copy_v2_v2(prev_co, coords[nr - 1]);
+ sub_v2_v2v2(prev_vec, prev_co, coords[nr - 2]);
+
+ for (int i = 0; i < nr; i++) {
+ sub_v2_v2v2(curr_vec, coords[i], prev_co);
+
+ if (len_squared_v2(curr_vec) < FLT_EPSILON) {
+ return MOD_SDEF_BIND_RESULT_OVERLAP_ERR;
+ }
+
+ if (1.0f - dot_v2v2(prev_vec, curr_vec) < FLT_EPSILON) {
+ return MOD_SDEF_BIND_RESULT_CONCAVE_ERR;
+ }
+
+ copy_v2_v2(prev_co, coords[i]);
+ copy_v2_v2(prev_vec, curr_vec);
+ }
+
+ return MOD_SDEF_BIND_RESULT_SUCCESS;
+}
+
+static void freeBindData(SDefBindWeightData * const bwdata)
+{
+ SDefBindPoly *bpoly = bwdata->bind_polys;
+
+ if (bwdata->bind_polys) {
+ for (int i = 0; i < bwdata->numpoly; bpoly++, i++) {
+ MEM_SAFE_FREE(bpoly->coords);
+ MEM_SAFE_FREE(bpoly->coords_v2);
+ }
+
+ MEM_freeN(bwdata->bind_polys);
+ }
+
+ MEM_freeN(bwdata);
+}
+
+BLI_INLINE float computeAngularWeight(const float point_angle, const float edgemid_angle)
+{
+ float weight;
+
+ weight = point_angle;
+ weight /= edgemid_angle;
+ weight *= M_PI_2;
+
+ return sinf(weight);
+}
+
+BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData * const data, const float point_co[3])
+{
+ const unsigned int nearest = nearestVert(data, point_co);
+ const SDefAdjacency * const vert_edges = data->vert_edges[nearest].first;
+ const SDefEdgePolys * const edge_polys = data->edge_polys;
+
+ const SDefAdjacency *vedge;
+ const MPoly *poly;
+ const MLoop *loop;
+
+ SDefBindWeightData *bwdata;
+ SDefBindPoly *bpoly;
+
+ float world[3] = {0.0f, 0.0f, 1.0f};
+ float avg_point_dist = 0.0f;
+ float tot_weight = 0.0f;
+ int inf_weight_flags = 0;
+
+ bwdata = MEM_callocN(sizeof(*bwdata), "SDefBindWeightData");
+ if (bwdata == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return NULL;
+ }
+
+ bwdata->numpoly = data->vert_edges[nearest].num / 2;
+
+ bpoly = MEM_callocN(sizeof(*bpoly) * bwdata->numpoly, "SDefBindPoly");
+ if (bpoly == NULL) {
+ freeBindData(bwdata);
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return NULL;
+ }
+
+ bwdata->bind_polys = bpoly;
+
+ /* Loop over all adjacent edges, and build the SDefBindPoly data for each poly adjacent to those */
+ for (vedge = vert_edges; vedge; vedge = vedge->next) {
+ unsigned int edge_ind = vedge->index;
+
+ for (int i = 0; i < edge_polys[edge_ind].num; i++) {
+ {
+ bpoly = bwdata->bind_polys;
+
+ for (int j = 0; j < bwdata->numpoly; bpoly++, j++) {
+ /* If coords isn't allocated, we have reached the first uninitialized bpoly */
+ if ((bpoly->index == edge_polys[edge_ind].polys[i]) || (!bpoly->coords)) {
+ break;
+ }
+ }
+ }
+
+ /* Check if poly was already created by another edge or still has to be initialized */
+ if (!bpoly->coords) {
+ float angle;
+ float axis[3];
+ float tmp_vec_v2[2];
+ int is_poly_valid;
+
+ bpoly->index = edge_polys[edge_ind].polys[i];
+ bpoly->coords = NULL;
+ bpoly->coords_v2 = NULL;
+
+ /* Copy poly data */
+ poly = &data->mpoly[bpoly->index];
+ loop = &data->mloop[poly->loopstart];
+
+ bpoly->numverts = poly->totloop;
+ bpoly->loopstart = poly->loopstart;
+
+ bpoly->coords = MEM_mallocN(sizeof(*bpoly->coords) * poly->totloop, "SDefBindPolyCoords");
+ if (bpoly->coords == NULL) {
+ freeBindData(bwdata);
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return NULL;
+ }
+
+ bpoly->coords_v2 = MEM_mallocN(sizeof(*bpoly->coords_v2) * poly->totloop, "SDefBindPolyCoords_v2");
+ if (bpoly->coords_v2 == NULL) {
+ freeBindData(bwdata);
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return NULL;
+ }
+
+ for (int j = 0; j < poly->totloop; j++, loop++) {
+ copy_v3_v3(bpoly->coords[j], data->targetCos[loop->v]);
+
+ /* Find corner and edge indices within poly loop array */
+ if (loop->v == nearest) {
+ bpoly->corner_ind = j;
+ bpoly->edge_vert_inds[0] = (j == 0) ? (poly->totloop - 1) : (j - 1);
+ bpoly->edge_vert_inds[1] = (j == poly->totloop - 1) ? (0) : (j + 1);
+
+ bpoly->edge_inds[0] = data->mloop[poly->loopstart + bpoly->edge_vert_inds[0]].e;
+ bpoly->edge_inds[1] = loop->e;
+ }
+ }
+
+ /* Compute poly's parametric data */
+ mid_v3_v3_array(bpoly->centroid, bpoly->coords, poly->totloop);
+ normal_poly_v3(bpoly->normal, bpoly->coords, poly->totloop);
+
+ /* Compute poly skew angle and axis */
+ angle = angle_normalized_v3v3(bpoly->normal, world);
+
+ cross_v3_v3v3(axis, bpoly->normal, world);
+ normalize_v3(axis);
+
+ /* Map coords onto 2d normal plane */
+ map_to_plane_axis_angle_v2_v3v3fl(bpoly->point_v2, point_co, axis, angle);
+
+ zero_v2(bpoly->centroid_v2);
+ for (int j = 0; j < poly->totloop; j++) {
+ map_to_plane_axis_angle_v2_v3v3fl(bpoly->coords_v2[j], bpoly->coords[j], axis, angle);
+ madd_v2_v2fl(bpoly->centroid_v2, bpoly->coords_v2[j], 1.0f / poly->totloop);
+ }
+
+ is_poly_valid = isPolyValid(bpoly->coords_v2, poly->totloop);
+
+ if (is_poly_valid != MOD_SDEF_BIND_RESULT_SUCCESS) {
+ freeBindData(bwdata);
+ data->success = is_poly_valid;
+ return NULL;
+ }
+
+ bpoly->inside = isect_point_poly_v2(bpoly->point_v2, bpoly->coords_v2, poly->totloop, false);
+
+ /* Initialize weight components */
+ bpoly->weight_angular = 1.0f;
+ bpoly->weight_dist_proj = len_v2v2(bpoly->centroid_v2, bpoly->point_v2);
+ bpoly->weight_dist = len_v3v3(bpoly->centroid, point_co);
+
+ avg_point_dist += bpoly->weight_dist;
+
+ /* Compute centroid to mid-edge vectors */
+ mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[0],
+ bpoly->coords_v2[bpoly->edge_vert_inds[0]],
+ bpoly->coords_v2[bpoly->corner_ind]);
+
+ mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[1],
+ bpoly->coords_v2[bpoly->edge_vert_inds[1]],
+ bpoly->coords_v2[bpoly->corner_ind]);
+
+ sub_v2_v2(bpoly->cent_edgemid_vecs_v2[0], bpoly->centroid_v2);
+ sub_v2_v2(bpoly->cent_edgemid_vecs_v2[1], bpoly->centroid_v2);
+
+ /* Compute poly scales with respect to mid-edges, and normalize the vectors */
+ bpoly->scales[0] = normalize_v2(bpoly->cent_edgemid_vecs_v2[0]);
+ bpoly->scales[1] = normalize_v2(bpoly->cent_edgemid_vecs_v2[1]);
+
+ /* Compute the required polygon angles */
+ bpoly->edgemid_angle = angle_normalized_v2v2(bpoly->cent_edgemid_vecs_v2[0], bpoly->cent_edgemid_vecs_v2[1]);
+
+ sub_v2_v2v2(tmp_vec_v2, bpoly->coords_v2[bpoly->corner_ind], bpoly->centroid_v2);
+ normalize_v2(tmp_vec_v2);
+
+ bpoly->corner_edgemid_angles[0] = angle_normalized_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[0]);
+ bpoly->corner_edgemid_angles[1] = angle_normalized_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[1]);
+
+ /* Check for inifnite weights, and compute angular data otherwise */
+ if (bpoly->weight_dist < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
+ }
+ else if (bpoly->weight_dist_proj < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
+ }
+ else {
+ float cent_point_vec[2];
+
+ sub_v2_v2v2(cent_point_vec, bpoly->point_v2, bpoly->centroid_v2);
+ normalize_v2(cent_point_vec);
+
+ bpoly->point_edgemid_angles[0] = angle_normalized_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[0]);
+ bpoly->point_edgemid_angles[1] = angle_normalized_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[1]);
+ }
+ }
+ }
+ }
+
+ avg_point_dist /= bwdata->numpoly;
+
+ /* If weights 1 and 2 are not infinite, loop over all adjacent edges again,
+ * and build adjacency dependent angle data (depends on all polygons having been computed) */
+ if (!inf_weight_flags) {
+ for (vedge = vert_edges; vedge; vedge = vedge->next) {
+ SDefBindPoly *bpolys[2];
+ const SDefEdgePolys *epolys;
+ float ang_weights[2];
+ unsigned int edge_ind = vedge->index;
+ unsigned int edge_on_poly[2];
+
+ epolys = &edge_polys[edge_ind];
+
+ /* Find bind polys corresponding to the edge's adjacent polys */
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0, j = 0; (i < bwdata->numpoly) && (j < epolys->num); bpoly++, i++) {
+ if (ELEM(bpoly->index, epolys->polys[0], epolys->polys[1])) {
+ bpolys[j] = bpoly;
+
+ if (bpoly->edge_inds[0] == edge_ind) {
+ edge_on_poly[j] = 0;
+ }
+ else {
+ edge_on_poly[j] = 1;
+ }
+
+ j++;
+ }
+ }
+
+ /* Compute angular weight component */
+ if (epolys->num == 1) {
+ ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]], bpolys[0]->edgemid_angle);
+ bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[0];
+ }
+ else if (epolys->num == 2) {
+ ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]], bpolys[0]->edgemid_angle);
+ ang_weights[1] = computeAngularWeight(bpolys[1]->point_edgemid_angles[edge_on_poly[1]], bpolys[1]->edgemid_angle);
+
+ bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[1];
+ bpolys[1]->weight_angular *= ang_weights[0] * ang_weights[1];
+ }
+ }
+ }
+
+ /* Compute scalings and falloff.
+ * Scale all weights if no infinite weight is found,
+ * scale only unprojected weight if projected weight is infinite,
+ * scale none if both are infinite. */
+ if (!inf_weight_flags) {
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0; i < bwdata->numpoly; bpoly++, i++) {
+ float corner_angle_weights[2];
+ float scale_weight, sqr, inv_sqr;
+
+ corner_angle_weights[0] = bpoly->point_edgemid_angles[0] / bpoly->corner_edgemid_angles[0];
+ corner_angle_weights[1] = bpoly->point_edgemid_angles[1] / bpoly->corner_edgemid_angles[1];
+
+ if (isnan(corner_angle_weights[0]) || isnan(corner_angle_weights[1])) {
+ freeBindData(bwdata);
+ data->success = MOD_SDEF_BIND_RESULT_GENERIC_ERR;
+ return NULL;
+ }
+
+ /* Find which edge the point is closer to */
+ if (corner_angle_weights[0] < corner_angle_weights[1]) {
+ bpoly->dominant_edge = 0;
+ bpoly->dominant_angle_weight = corner_angle_weights[0];
+ }
+ else {
+ bpoly->dominant_edge = 1;
+ bpoly->dominant_angle_weight = corner_angle_weights[1];
+ }
+
+ bpoly->dominant_angle_weight = sinf(bpoly->dominant_angle_weight * M_PI_2);
+
+ /* Compute quadratic angular scale interpolation weight */
+ scale_weight = bpoly->point_edgemid_angles[bpoly->dominant_edge] / bpoly->edgemid_angle;
+ scale_weight /= scale_weight + (bpoly->point_edgemid_angles[!bpoly->dominant_edge] / bpoly->edgemid_angle);
+
+ sqr = scale_weight * scale_weight;
+ inv_sqr = 1.0f - scale_weight;
+ inv_sqr *= inv_sqr;
+ scale_weight = sqr / (sqr + inv_sqr);
+
+ /* Compute interpolated scale (no longer need the individual scales,
+ * so simply storing the result over the scale in index zero) */
+ bpoly->scales[0] = bpoly->scales[bpoly->dominant_edge] * (1.0f - scale_weight) +
+ bpoly->scales[!bpoly->dominant_edge] * scale_weight;
+
+ /* Scale the point distance weights, and introduce falloff */
+ bpoly->weight_dist_proj /= bpoly->scales[0];
+ bpoly->weight_dist_proj = powf(bpoly->weight_dist_proj, data->falloff);
+
+ bpoly->weight_dist /= avg_point_dist;
+ bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff);
+
+ /* Re-check for infinite weights, now that all scalings and interpolations are computed */
+ if (bpoly->weight_dist < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
+ }
+ else if (bpoly->weight_dist_proj < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
+ }
+ else if (bpoly->weight_angular < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_ANGULAR;
+ }
+ }
+ }
+ else if (!(inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST)) {
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0; i < bwdata->numpoly; bpoly++, i++) {
+ /* Scale the point distance weight by average point distance, and introduce falloff */
+ bpoly->weight_dist /= avg_point_dist;
+ bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff);
+
+ /* Re-check for infinite weights, now that all scalings and interpolations are computed */
+ if (bpoly->weight_dist < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
+ }
+ }
+ }
+
+ /* Final loop, to compute actual weights */
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0; i < bwdata->numpoly; bpoly++, i++) {
+ /* Weight computation from components */
+ if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST) {
+ bpoly->weight = bpoly->weight_dist < FLT_EPSILON ? 1.0f : 0.0f;
+ }
+ else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ) {
+ bpoly->weight = bpoly->weight_dist_proj < FLT_EPSILON ?
+ 1.0f / bpoly->weight_dist : 0.0f;
+ }
+ else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_ANGULAR) {
+ bpoly->weight = bpoly->weight_angular < FLT_EPSILON ?
+ 1.0f / bpoly->weight_dist_proj / bpoly->weight_dist : 0.0f;
+ }
+ else {
+ bpoly->weight = 1.0f / bpoly->weight_angular /
+ bpoly->weight_dist_proj /
+ bpoly->weight_dist;
+ }
+
+ tot_weight += bpoly->weight;
+ }
+
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0; i < bwdata->numpoly; bpoly++, i++) {
+ bpoly->weight /= tot_weight;
+
+ /* Evaluate if this poly is relevant to bind */
+ /* Even though the weights should add up to 1.0,
+ * the losses of weights smaller than epsilon here
+ * should be negligible... */
+ if (bpoly->weight >= FLT_EPSILON) {
+ if (bpoly->inside) {
+ bwdata->numbinds += 1;
+ }
+ else {
+ if (bpoly->dominant_angle_weight < FLT_EPSILON || 1.0f - bpoly->dominant_angle_weight < FLT_EPSILON) {
+ bwdata->numbinds += 1;
+ }
+ else {
+ bwdata->numbinds += 2;
+ }
+ }
+ }
+ }
+
+ return bwdata;
+}
+
+BLI_INLINE float computeNormalDisplacement(const float point_co[3], const float point_co_proj[3], const float normal[3])
+{
+ float disp_vec[3];
+ float normal_dist;
+
+ sub_v3_v3v3(disp_vec, point_co, point_co_proj);
+ normal_dist = len_v3(disp_vec);
+
+ if (dot_v3v3(disp_vec, normal) < 0) {
+ normal_dist *= -1;
+ }
+
+ return normal_dist;
+}
+
+static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
+{
+ SDefBindCalcData * const data = (SDefBindCalcData *)userdata;
+ float point_co[3];
+ float point_co_proj[3];
+
+ SDefBindWeightData *bwdata;
+ SDefVert *sdvert = data->bind_verts + index;
+ SDefBindPoly *bpoly;
+ SDefBind *sdbind;
+
+ if (data->success != MOD_SDEF_BIND_RESULT_SUCCESS) {
+ sdvert->binds = NULL;
+ sdvert->numbinds = 0;
+ return;
+ }
+
+ copy_v3_v3(point_co, data->vertexCos[index]);
+ bwdata = computeBindWeights(data, point_co);
+
+ if (bwdata == NULL) {
+ sdvert->binds = NULL;
+ sdvert->numbinds = 0;
+ return;
+ }
+
+ sdvert->binds = MEM_callocN(sizeof(*sdvert->binds) * bwdata->numbinds, "SDefVertBindData");
+ if (sdvert->binds == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ sdvert->numbinds = 0;
+ return;
+ }
+
+ sdvert->numbinds = bwdata->numbinds;
+
+ sdbind = sdvert->binds;
+
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0; i < bwdata->numbinds; bpoly++) {
+ if (bpoly->weight >= FLT_EPSILON) {
+ if (bpoly->inside) {
+ const MLoop *loop = &data->mloop[bpoly->loopstart];
+
+ sdbind->influence = bpoly->weight;
+ sdbind->numverts = bpoly->numverts;
+
+ sdbind->mode = MOD_SDEF_MODE_NGON;
+ sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * bpoly->numverts, "SDefNgonVertWeights");
+ if (sdbind->vert_weights == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefNgonVertInds");
+ if (sdbind->vert_inds == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ interp_weights_poly_v2(sdbind->vert_weights, bpoly->coords_v2, bpoly->numverts, bpoly->point_v2);
+
+ /* Reproject vert based on weights and original poly verts, to reintroduce poly non-planarity */
+ zero_v3(point_co_proj);
+ for (int j = 0; j < bpoly->numverts; j++, loop++) {
+ madd_v3_v3fl(point_co_proj, bpoly->coords[j], sdbind->vert_weights[j]);
+ sdbind->vert_inds[j] = loop->v;
+ }
+
+ sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
+
+ sdbind++;
+ i++;
+ }
+ else {
+ float tmp_vec[3];
+ float cent[3], norm[3];
+ float v1[3], v2[3], v3[3];
+
+ if (1.0f - bpoly->dominant_angle_weight >= FLT_EPSILON) {
+ sdbind->influence = bpoly->weight * (1.0f - bpoly->dominant_angle_weight);
+ sdbind->numverts = bpoly->numverts;
+
+ sdbind->mode = MOD_SDEF_MODE_CENTROID;
+ sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * 3, "SDefCentVertWeights");
+ if (sdbind->vert_weights == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefCentVertInds");
+ if (sdbind->vert_inds == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ sortPolyVertsEdge(sdbind->vert_inds, &data->mloop[bpoly->loopstart],
+ bpoly->edge_inds[bpoly->dominant_edge], bpoly->numverts);
+
+ copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]);
+ copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]);
+ copy_v3_v3(v3, bpoly->centroid);
+
+ mid_v3_v3v3v3(cent, v1, v2, v3);
+ normal_tri_v3(norm, v1, v2, v3);
+
+ add_v3_v3v3(tmp_vec, point_co, bpoly->normal);
+
+ /* We are sure the line is not parallel to the plane.
+ * Checking return value just to avoid warning... */
+ if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) {
+ BLI_assert(false);
+ }
+
+ interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj);
+
+ sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
+
+ sdbind++;
+ i++;
+ }
+
+ if (bpoly->dominant_angle_weight >= FLT_EPSILON) {
+ sdbind->influence = bpoly->weight * bpoly->dominant_angle_weight;
+ sdbind->numverts = bpoly->numverts;
+
+ sdbind->mode = MOD_SDEF_MODE_LOOPTRI;
+ sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * 3, "SDefTriVertWeights");
+ if (sdbind->vert_weights == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefTriVertInds");
+ if (sdbind->vert_inds == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ sortPolyVertsTri(sdbind->vert_inds, &data->mloop[bpoly->loopstart], bpoly->edge_vert_inds[0], bpoly->numverts);
+
+ copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]);
+ copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]);
+ copy_v3_v3(v3, data->targetCos[sdbind->vert_inds[2]]);
+
+ mid_v3_v3v3v3(cent, v1, v2, v3);
+ normal_tri_v3(norm, v1, v2, v3);
+
+ add_v3_v3v3(tmp_vec, point_co, bpoly->normal);
+
+ /* We are sure the line is not parallel to the plane.
+ * Checking return value just to avoid warning... */
+ if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) {
+ BLI_assert(false);
+ }
+
+ interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj);
+
+ sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
+
+ sdbind++;
+ i++;
+ }
+ }
+ }
+ }
+
+ freeBindData(bwdata);
+}
+
+static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos)[3],
+ unsigned int numverts, unsigned int tnumpoly, unsigned int tnumverts, DerivedMesh *tdm)
+{
+ BVHTreeFromMesh treeData = {NULL};
+ const MVert *mvert = tdm->getVertArray(tdm);
+ const MPoly *mpoly = tdm->getPolyArray(tdm);
+ const MEdge *medge = tdm->getEdgeArray(tdm);
+ const MLoop *mloop = tdm->getLoopArray(tdm);
+ unsigned int tnumedges = tdm->getNumEdges(tdm);
+ int adj_result;
+ SDefAdjacencyArray *vert_edges;
+ SDefAdjacency *adj_array;
+ SDefEdgePolys *edge_polys;
+
+ vert_edges = MEM_callocN(sizeof(*vert_edges) * tnumverts, "SDefVertEdgeMap");
+ if (vert_edges == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ return false;
+ }
+
+ adj_array = MEM_mallocN(sizeof(*adj_array) * tnumedges * 2, "SDefVertEdge");
+ if (adj_array == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ MEM_freeN(vert_edges);
+ return false;
+ }
+
+ edge_polys = MEM_callocN(sizeof(*edge_polys) * tnumedges, "SDefEdgeFaceMap");
+ if (edge_polys == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ MEM_freeN(vert_edges);
+ MEM_freeN(adj_array);
+ return false;
+ }
+
+ smd->verts = MEM_mallocN(sizeof(*smd->verts) * numverts, "SDefBindVerts");
+ if (smd->verts == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ freeAdjacencyMap(vert_edges, adj_array, edge_polys);
+ return false;
+ }
+
+ bvhtree_from_mesh_looptri(&treeData, tdm, 0.0, 2, 6);
+ if (treeData.tree == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ freeAdjacencyMap(vert_edges, adj_array, edge_polys);
+ MEM_freeN(smd->verts);
+ smd->verts = NULL;
+ return false;
+ }
+
+ adj_result = buildAdjacencyMap(mpoly, medge, mloop, tnumpoly, tnumedges, vert_edges, adj_array, edge_polys);
+
+ if (adj_result == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
+ modifier_setError((ModifierData *)smd, "Target has edges with more than two polygons");
+ freeAdjacencyMap(vert_edges, adj_array, edge_polys);
+ free_bvhtree_from_mesh(&treeData);
+ MEM_freeN(smd->verts);
+ smd->verts = NULL;
+ return false;
+ }
+
+ smd->numverts = numverts;
+ smd->numpoly = tnumpoly;
+
+ SDefBindCalcData data = {.treeData = &treeData,
+ .vert_edges = vert_edges,
+ .edge_polys = edge_polys,
+ .mpoly = mpoly,
+ .medge = medge,
+ .mloop = mloop,
+ .looptri = tdm->getLoopTriArray(tdm),
+ .targetCos = MEM_mallocN(sizeof(float[3]) * tnumverts, "SDefTargetBindVertArray"),
+ .bind_verts = smd->verts,
+ .vertexCos = vertexCos,
+ .falloff = smd->falloff,
+ .success = MOD_SDEF_BIND_RESULT_SUCCESS};
+
+ if (data.targetCos == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ freeData((ModifierData *)smd);
+ return false;
+ }
+
+ invert_m4_m4(data.imat, smd->mat);
+
+ for (int i = 0; i < tnumverts; i++) {
+ mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co);
+ }
+
+ BLI_task_parallel_range_ex(0, numverts, &data, NULL, 0, bindVert,
+ numverts > 10000, false);
+
+ MEM_freeN(data.targetCos);
+
+ if (data.success == MOD_SDEF_BIND_RESULT_MEM_ERR) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ freeData((ModifierData *)smd);
+ }
+ else if (data.success == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
+ modifier_setError((ModifierData *)smd, "Target has edges with more than two polygons");
+ freeData((ModifierData *)smd);
+ }
+ else if (data.success == MOD_SDEF_BIND_RESULT_CONCAVE_ERR) {
+ modifier_setError((ModifierData *)smd, "Target contains concave polygons");
+ freeData((ModifierData *)smd);
+ }
+ else if (data.success == MOD_SDEF_BIND_RESULT_OVERLAP_ERR) {
+ modifier_setError((ModifierData *)smd, "Target contains overlapping verts");
+ freeData((ModifierData *)smd);
+ }
+ else if (data.success == MOD_SDEF_BIND_RESULT_GENERIC_ERR) {
+ /* I know this message is vague, but I could not think of a way
+ * to explain this whith a reasonably sized message.
+ * Though it shouldn't really matter all that much,
+ * because this is very unlikely to occur */
+ modifier_setError((ModifierData *)smd, "Target contains invalid polygons");
+ freeData((ModifierData *)smd);
+ }
+
+ freeAdjacencyMap(vert_edges, adj_array, edge_polys);
+ free_bvhtree_from_mesh(&treeData);
+
+ return data.success == 1;
+}
+
+static void deformVert(void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
+{
+ const SDefDeformData * const data = (SDefDeformData *)userdata;
+ const SDefBind *sdbind = data->bind_verts[index].binds;
+ float * const vertexCos = data->vertexCos[index];
+ float norm[3], temp[3];
+
+ zero_v3(vertexCos);
+
+ for (int j = 0; j < data->bind_verts[index].numbinds; j++, sdbind++) {
+ /* Mode-generic operations (allocate poly coordinates) */
+ float (*coords)[3] = MEM_mallocN(sizeof(*coords) * sdbind->numverts, "SDefDoPolyCoords");
+
+ for (int k = 0; k < sdbind->numverts; k++) {
+ copy_v3_v3(coords[k], data->targetCos[sdbind->vert_inds[k]]);
+ }
+
+ normal_poly_v3(norm, coords, sdbind->numverts);
+ zero_v3(temp);
+
+ /* ---------- looptri mode ---------- */
+ if (sdbind->mode == MOD_SDEF_MODE_LOOPTRI) {
+ madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]);
+ madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]);
+ madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[2]], sdbind->vert_weights[2]);
+ }
+ else {
+ /* ---------- ngon mode ---------- */
+ if (sdbind->mode == MOD_SDEF_MODE_NGON) {
+ for (int k = 0; k < sdbind->numverts; k++) {
+ madd_v3_v3fl(temp, coords[k], sdbind->vert_weights[k]);
+ }
+ }
+
+ /* ---------- centroid mode ---------- */
+ else if (sdbind->mode == MOD_SDEF_MODE_CENTROID) {
+ float cent[3];
+ mid_v3_v3_array(cent, coords, sdbind->numverts);
+
+ madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]);
+ madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]);
+ madd_v3_v3fl(temp, cent, sdbind->vert_weights[2]);
+ }
+ }
+
+ MEM_freeN(coords);
+
+ /* Apply normal offset (generic for all modes) */
+ madd_v3_v3fl(temp, norm, sdbind->normal_dist);
+
+ madd_v3_v3fl(vertexCos, temp, sdbind->influence);
+ }
+}
+
+static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], unsigned int numverts, Object *ob)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ DerivedMesh *tdm;
+ unsigned int tnumverts, tnumpoly;
+
+ /* Exit function if bind flag is not set (free bind data if any) */
+ if (!(smd->flags & MOD_SDEF_BIND)) {
+ freeData(md);
+ return;
+ }
+
+ /* Handle target mesh both in and out of edit mode */
+ if (smd->target == md->scene->obedit) {
+ BMEditMesh *em = BKE_editmesh_from_object(smd->target);
+ tdm = em->derivedFinal;
+ }
+ else {
+ tdm = smd->target->derivedFinal;
+ }
+
+ if (!tdm) {
+ modifier_setError(md, "No valid target mesh");
+ return;
+ }
+
+ tnumverts = tdm->getNumVerts(tdm);
+ tnumpoly = tdm->getNumPolys(tdm);
+
+ /* If not bound, execute bind */
+ if (!(smd->verts)) {
+ float tmp_mat[4][4];
+
+ invert_m4_m4(tmp_mat, ob->obmat);
+ mul_m4_m4m4(smd->mat, tmp_mat, smd->target->obmat);
+
+ if (!surfacedeformBind(smd, vertexCos, numverts, tnumpoly, tnumverts, tdm)) {
+ smd->flags &= ~MOD_SDEF_BIND;
+ return;
+ }
+ }
+
+ /* Poly count checks */
+ if (smd->numverts != numverts) {
+ modifier_setError(md, "Verts changed from %u to %u", smd->numverts, numverts);
+ return;
+ }
+ else if (smd->numpoly != tnumpoly) {
+ modifier_setError(md, "Target polygons changed from %u to %u", smd->numpoly, tnumpoly);
+ return;
+ }
+
+ /* Actual vertex location update starts here */
+ SDefDeformData data = {
+ .bind_verts = smd->verts,
+ .targetCos = MEM_mallocN(sizeof(float[3]) * tnumverts, "SDefTargetVertArray"),
+ .vertexCos = vertexCos,
+ };
+
+ if (data.targetCos != NULL) {
+ bool tdm_vert_alloc;
+ const MVert * const mvert = DM_get_vert_array(tdm, &tdm_vert_alloc);
+
+ for (int i = 0; i < tnumverts; i++) {
+ mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co);
+ }
+
+ BLI_task_parallel_range_ex(0, numverts, &data, NULL, 0, deformVert,
+ numverts > 10000, false);
+
+ if (tdm_vert_alloc) {
+ MEM_freeN((void *)mvert);
+ }
+
+ MEM_freeN(data.targetCos);
+ }
+}
+
+static void deformVerts(ModifierData *md, Object *ob,
+ DerivedMesh *UNUSED(derivedData),
+ float (*vertexCos)[3], int numVerts,
+ ModifierApplyFlag UNUSED(flag))
+{
+ surfacedeformModifier_do(md, vertexCos, numVerts, ob);
+}
+
+static void deformVertsEM(ModifierData *md, Object *ob,
+ struct BMEditMesh *UNUSED(editData),
+ DerivedMesh *UNUSED(derivedData),
+ float (*vertexCos)[3], int numVerts)
+{
+ surfacedeformModifier_do(md, vertexCos, numVerts, ob);
+}
+
+static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+
+ return !smd->target && !(smd->verts && !(smd->flags & MOD_SDEF_BIND));
+}
+
+ModifierTypeInfo modifierType_SurfaceDeform = {
+ /* name */ "Surface Deform",
+ /* structName */ "SurfaceDeformModifierData",
+ /* structSize */ sizeof(SurfaceDeformModifierData),
+ /* type */ eModifierTypeType_OnlyDeform,
+ /* flags */ eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+ /* deformVerts */ deformVerts,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ deformVertsEM,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ NULL,
+ /* applyModifierEM */ NULL,
+ /* initData */ initData,
+ /* requiredDataMask */ NULL,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 6fad2756f82..b057d6d5a86 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -35,6 +35,8 @@
#include "bmesh.h"
#include "bmesh_tools.h"
+#include "MOD_modifiertypes.h"
+
static DerivedMesh *triangulate_dm(DerivedMesh *dm, const int quad_method, const int ngon_method)
{
DerivedMesh *result;
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 93414562ccf..ded1f0b77e6 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -287,5 +287,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(NormalEdit);
INIT_TYPE(CorrectiveSmooth);
INIT_TYPE(MeshSequenceCache);
+ INIT_TYPE(SurfaceDeform);
#undef INIT_TYPE
}
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index fb7668d16e0..01468c1143a 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -45,6 +45,7 @@
#include "BKE_camera.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_mesh.h"
#include "BKE_DerivedMesh.h"
@@ -70,9 +71,12 @@ static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
UVProjectModifierData *umd = (UVProjectModifierData *) md;
- UVProjectModifierData *tumd = (UVProjectModifierData *) target;
#endif
+ UVProjectModifierData *tumd = (UVProjectModifierData *) target;
+
modifier_copyData_generic(md, target);
+
+ id_us_plus((ID *)tumd->image);
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md))
@@ -92,7 +96,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
int i;
for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i)
- walk(userData, ob, &umd->projectors[i], IDWALK_NOP);
+ walk(userData, ob, &umd->projectors[i], IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -100,7 +104,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
UVProjectModifierData *umd = (UVProjectModifierData *) md;
- walk(userData, ob, (ID **)&umd->image, IDWALK_USER);
+ walk(userData, ob, (ID **)&umd->image, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index 89994c3ae22..b3fc3842635 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -221,8 +221,8 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
UVWarpModifierData *umd = (UVWarpModifierData *) md;
- walk(userData, ob, &umd->object_dst, IDWALK_NOP);
- walk(userData, ob, &umd->object_src, IDWALK_NOP);
+ walk(userData, ob, &umd->object_dst, IDWALK_CB_NOP);
+ walk(userData, ob, &umd->object_src, IDWALK_CB_NOP);
}
static void uv_warp_deps_object_bone(DagForest *forest, DagNode *obNode,
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index b38de140a91..b340356467a 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -66,6 +66,10 @@ static void copyData(ModifierData *md, ModifierData *target)
WarpModifierData *wmd = (WarpModifierData *) md;
WarpModifierData *twmd = (WarpModifierData *) target;
+ if (twmd->curfalloff != NULL) {
+ curvemapping_free(twmd->curfalloff);
+ }
+
modifier_copyData_generic(md, target);
twmd->curfalloff = curvemapping_copy(wmd->curfalloff);
@@ -116,16 +120,16 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
WarpModifierData *wmd = (WarpModifierData *) md;
- walk(userData, ob, &wmd->object_from, IDWALK_NOP);
- walk(userData, ob, &wmd->object_to, IDWALK_NOP);
- walk(userData, ob, &wmd->map_object, IDWALK_NOP);
+ walk(userData, ob, &wmd->object_from, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->object_to, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WarpModifierData *wmd = (WarpModifierData *) md;
- walk(userData, ob, (ID **)&wmd->texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 683649ed1c0..b4990c5250e 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -90,14 +90,10 @@ static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
WaveModifierData *wmd = (WaveModifierData *) md;
-#endif
WaveModifierData *twmd = (WaveModifierData *) target;
+#endif
modifier_copyData_generic(md, target);
-
- if (twmd->texture) {
- id_us_plus(&twmd->texture->id);
- }
}
static bool dependsOnTime(ModifierData *UNUSED(md))
@@ -111,8 +107,8 @@ static void foreachObjectLink(
{
WaveModifierData *wmd = (WaveModifierData *) md;
- walk(userData, ob, &wmd->objectcenter, IDWALK_NOP);
- walk(userData, ob, &wmd->map_object, IDWALK_NOP);
+ walk(userData, ob, &wmd->objectcenter, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -120,7 +116,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
WaveModifierData *wmd = (WaveModifierData *) md;
- walk(userData, ob, (ID **)&wmd->texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index 93567aed2c4..13a97c1c13d 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -50,7 +50,9 @@
#include "DEG_depsgraph_build.h"
#include "MEM_guardedalloc.h"
+
#include "MOD_weightvg_util.h"
+#include "MOD_modifiertypes.h"
/**************************************
* Modifiers functions. *
@@ -91,10 +93,6 @@ static void copyData(ModifierData *md, ModifierData *target)
modifier_copyData_generic(md, target);
twmd->cmap_curve = curvemapping_copy(wmd->cmap_curve);
-
- if (twmd->mask_texture) {
- id_us_plus(&twmd->mask_texture->id);
- }
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
@@ -126,14 +124,14 @@ static bool dependsOnTime(ModifierData *md)
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
- walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
@@ -226,8 +224,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
if (!do_add)
return dm;
/* Else, add a valid data layer! */
- dvert = CustomData_add_layer_named(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC,
- NULL, numVerts, wmd->defgrp_name);
+ dvert = CustomData_add_layer(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
/* Ultimate security check. */
if (!dvert)
return dm;
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 170fbbed7f1..392f42040b0 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -47,7 +47,9 @@
#include "DEG_depsgraph_build.h"
#include "MEM_guardedalloc.h"
+
#include "MOD_weightvg_util.h"
+#include "MOD_modifiertypes.h"
/**
@@ -136,14 +138,10 @@ static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
-#endif
WeightVGMixModifierData *twmd = (WeightVGMixModifierData *) target;
+#endif
modifier_copyData_generic(md, target);
-
- if (twmd->mask_texture) {
- id_us_plus(&twmd->mask_texture->id);
- }
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
@@ -175,14 +173,14 @@ static bool dependsOnTime(ModifierData *md)
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
@@ -282,8 +280,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
if (wmd->mix_set != MOD_WVG_SET_ALL)
return dm;
/* Else, add a valid data layer! */
- dvert = CustomData_add_layer_named(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC,
- NULL, numVerts, wmd->defgrp_name_a);
+ dvert = CustomData_add_layer(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
/* Ultimate security check. */
if (!dvert)
return dm;
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index af59f11ba15..2ca380ba5c2 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -51,7 +51,9 @@
#include "DEG_depsgraph_build.h"
#include "MEM_guardedalloc.h"
+
#include "MOD_weightvg_util.h"
+#include "MOD_modifiertypes.h"
//#define USE_TIMEIT
@@ -286,14 +288,10 @@ static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
-#endif
WeightVGProximityModifierData *twmd = (WeightVGProximityModifierData *) target;
+#endif
modifier_copyData_generic(md, target);
-
- if (twmd->mask_texture) {
- id_us_plus(&twmd->mask_texture->id);
- }
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
@@ -325,15 +323,15 @@ static bool dependsOnTime(ModifierData *md)
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- walk(userData, ob, &wmd->proximity_ob_target, IDWALK_NOP);
- walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
+ walk(userData, ob, &wmd->proximity_ob_target, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index d20881df150..c5a3c70100b 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -163,6 +163,7 @@ set(SRC
shader/nodes/node_shader_background.c
shader/nodes/node_shader_bsdf_anisotropic.c
shader/nodes/node_shader_bsdf_diffuse.c
+ shader/nodes/node_shader_bsdf_principled.c
shader/nodes/node_shader_bsdf_glass.c
shader/nodes/node_shader_bsdf_glossy.c
shader/nodes/node_shader_bsdf_toon.c
@@ -288,8 +289,4 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
-if(WITH_CYCLES AND WITH_CYCLES_DEBUG)
- add_definitions(-DWITH_CYCLES_DEBUG)
-endif()
-
blender_add_lib(bf_nodes "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 0215db1dd55..a5c2e604f46 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -139,6 +139,8 @@ void register_node_type_cmp_trackpos(void);
void register_node_type_cmp_planetrackdeform(void);
void register_node_type_cmp_cornerpin(void);
-void node_cmp_rlayers_force_hidden_passes(struct bNode *node);
+void node_cmp_rlayers_outputs(struct bNodeTree *ntree, struct bNode *node);
+void node_cmp_rlayers_register_pass(struct bNodeTree *ntree, struct bNode *node, struct Scene *scene, struct SceneRenderLayer *srl, const char *name, int type);
+const char *node_cmp_rlayers_sock_to_pass(int sock_index);
#endif
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 4c0047f1d58..804c1897a27 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -106,6 +106,7 @@ void register_node_type_sh_bsdf_transparent(void);
void register_node_type_sh_bsdf_velvet(void);
void register_node_type_sh_bsdf_toon(void);
void register_node_type_sh_bsdf_anisotropic(void);
+void register_node_type_sh_bsdf_principled(void);
void register_node_type_sh_emission(void);
void register_node_type_sh_holdout(void);
void register_node_type_sh_volume_absorption(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 171d5313c1d..02422a8622a 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -80,6 +80,7 @@ DefNode( ShaderNode, SH_NODE_BACKGROUND, 0, "BA
DefNode( ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "" )
DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" )
+DefNode( ShaderNode, SH_NODE_BSDF_PRINCIPLED, def_principled, "BSDF_PRINCIPLED", BsdfPrincipled, "Principled 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_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
@@ -145,7 +146,7 @@ DefNode( CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBL
DefNode( CompositorNode, CMP_NODE_SEPRGBA, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
DefNode( CompositorNode, CMP_NODE_SEPHSVA, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
DefNode( CompositorNode, CMP_NODE_SETALPHA, 0, "SETALPHA", SetAlpha, "Set Alpha", "" )
-DefNode( CompositorNode, CMP_NODE_HUE_SAT, def_cmp_hue_saturation, "HUE_SAT", HueSat, "Hue Saturation Value","" )
+DefNode( CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SAT", HueSat, "Hue Saturation Value","" )
DefNode( CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" )
DefNode( CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" )
DefNode( CompositorNode, CMP_NODE_COMPOSITE, def_cmp_composite, "COMPOSITE", Composite, "Composite", "" )
@@ -178,7 +179,7 @@ DefNode( CompositorNode, CMP_NODE_DISPLACE, 0, "DISPL
DefNode( CompositorNode, CMP_NODE_COMBHSVA, 0, "COMBHSVA", CombHSVA, "Combine HSVA", "" )
DefNode( CompositorNode, CMP_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode( CompositorNode, CMP_NODE_LUMA_MATTE, def_cmp_luma_matte, "LUMA_MATTE", LumaMatte, "Luminance Key", "" )
-DefNode( CompositorNode, CMP_NODE_BRIGHTCONTRAST, 0, "BRIGHTCONTRAST", BrightContrast, "Bright/Contrast", "" )
+DefNode( CompositorNode, CMP_NODE_BRIGHTCONTRAST, def_cmp_brightcontrast, "BRIGHTCONTRAST", BrightContrast, "Bright/Contrast", "" )
DefNode( CompositorNode, CMP_NODE_GAMMA, 0, "GAMMA", Gamma, "Gamma", "" )
DefNode( CompositorNode, CMP_NODE_INVERT, def_cmp_invert, "INVERT", Invert, "Invert", "" )
DefNode( CompositorNode, CMP_NODE_NORMALIZE, 0, "NORMALIZE", Normalize, "Normalize", "" )
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c
index cb565bd5491..36778a18f77 100644
--- a/source/blender/nodes/composite/node_composite_tree.c
+++ b/source/blender/nodes/composite/node_composite_tree.c
@@ -240,8 +240,15 @@ void ntreeCompositExecTree(Scene *scene, bNodeTree *ntree, RenderData *rd, int r
/* *********************************************** */
-/* based on rules, force sockets hidden always */
-void ntreeCompositForceHidden(bNodeTree *ntree)
+/* Update the outputs of the render layer nodes.
+ * Since the outputs depend on the render engine, this part is a bit complex:
+ * - ntreeCompositUpdateRLayers is called and loops over all render layer nodes
+ * - Each render layer node calls the update function of the render engine that's used for its scene
+ * - The render engine calls RE_engine_register_pass for each pass
+ * - RE_engine_register_pass calls ntreeCompositRegisterPass,
+ * which calls node_cmp_rlayers_register_pass for every render layer node
+ */
+void ntreeCompositUpdateRLayers(bNodeTree *ntree)
{
bNode *node;
@@ -249,16 +256,20 @@ void ntreeCompositForceHidden(bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = node->next) {
if (node->type == CMP_NODE_R_LAYERS)
- node_cmp_rlayers_force_hidden_passes(node);
-
- /* XXX this stuff is called all the time, don't want that.
- * Updates should only happen when actually necessary.
- */
-#if 0
- else if (node->type == CMP_NODE_IMAGE) {
- nodeUpdate(ntree, node);
- }
-#endif
+ node_cmp_rlayers_outputs(ntree, node);
+ }
+
+}
+
+void ntreeCompositRegisterPass(bNodeTree *ntree, Scene *scene, SceneRenderLayer *srl, const char *name, int type)
+{
+ bNode *node;
+
+ if (ntree == NULL) return;
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_R_LAYERS)
+ node_cmp_rlayers_register_pass(ntree, node, scene, srl, name, type);
}
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c
index 2ad097013ef..fde7dccb4ac 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c
+++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c
@@ -47,6 +47,7 @@ static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *no
{
NodeBilateralBlurData *nbbd = MEM_callocN(sizeof(NodeBilateralBlurData), "node bilateral blur data");
node->storage = nbbd;
+ nbbd->iter = 1;
nbbd->sigma_color = 0.3;
nbbd->sigma_space = 5.0;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.c b/source/blender/nodes/composite/nodes/node_composite_brightness.c
index 62f23f417b2..26e4d3a52c9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_brightness.c
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.c
@@ -46,6 +46,10 @@ static bNodeSocketTemplate cmp_node_brightcontrast_out[] = {
{ -1, 0, "" }
};
+static void node_composit_init_brightcontrast(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = 1;
+}
void register_node_type_cmp_brightcontrast(void)
{
@@ -53,6 +57,7 @@ void register_node_type_cmp_brightcontrast(void)
cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, cmp_node_brightcontrast_in, cmp_node_brightcontrast_out);
+ node_type_init(&ntype, node_composit_init_brightcontrast);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_directionalblur.c b/source/blender/nodes/composite/nodes/node_composite_directionalblur.c
index 6eb27a228ad..336eb3409ff 100644
--- a/source/blender/nodes/composite/nodes/node_composite_directionalblur.c
+++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.c
@@ -46,6 +46,7 @@ static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeDBlurData *ndbd = MEM_callocN(sizeof(NodeDBlurData), "node dblur data");
node->storage = ndbd;
+ ndbd->iter = 1;
ndbd->center_x = 0.5;
ndbd->center_y = 0.5;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.c b/source/blender/nodes/composite/nodes/node_composite_glare.c
index c512ea49586..76020e55463 100644
--- a/source/blender/nodes/composite/nodes/node_composite_glare.c
+++ b/source/blender/nodes/composite/nodes/node_composite_glare.c
@@ -50,7 +50,8 @@ static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
ndg->colmod = 0.25;
ndg->mix = 0;
ndg->threshold = 1;
- ndg->angle = 4;
+ ndg->star_45 = true;
+ ndg->streaks = 4;
ndg->angle_ofs = 0.0f;
ndg->fade = 0.9;
ndg->size = 8;
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
index 1c31f4863ca..952ba78aff3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
+++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
@@ -35,8 +35,11 @@
/* **************** Hue Saturation ******************** */
static bNodeSocketTemplate cmp_node_hue_sat_in[] = {
- { SOCK_FLOAT, 1, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Hue"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Saturation"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Value"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ -1, 0, "" }
};
static bNodeSocketTemplate cmp_node_hue_sat_out[] = {
@@ -44,23 +47,12 @@ static bNodeSocketTemplate cmp_node_hue_sat_out[] = {
{ -1, 0, "" }
};
-static void node_composit_init_hue_sat(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeHueSat *nhs = MEM_callocN(sizeof(NodeHueSat), "node hue sat");
- node->storage = nhs;
- nhs->hue = 0.5f;
- nhs->sat = 1.0f;
- nhs->val = 1.0f;
-}
-
void register_node_type_cmp_hue_sat(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, cmp_node_hue_sat_in, cmp_node_hue_sat_out);
- node_type_init(&ntype, node_composit_init_hue_sat);
- node_type_storage(&ntype, "NodeHueSat", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
index 4f02c106569..a95c3233132 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -32,192 +32,108 @@
#include "node_composite_util.h"
#include "BLI_utildefines.h"
+#include "BLI_linklist.h"
#include "DNA_scene_types.h"
+#include "RE_engine.h"
+
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
-#ifdef WITH_CYCLES_DEBUG
-# include "RE_pipeline.h"
-#endif
-
/* **************** IMAGE (and RenderResult, multilayer image) ******************** */
static bNodeSocketTemplate cmp_node_rlayers_out[] = {
- { SOCK_RGBA, 0, N_("Image"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Z"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_VECTOR, 0, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_VECTOR, 0, N_("UV"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_VECTOR, 0, N_("Speed"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Diffuse"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Specular"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Shadow"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("AO"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Reflect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Refract"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Indirect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("IndexOB"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("IndexMA"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Mist"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Emit"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Environment"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Diffuse Direct"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Diffuse Indirect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Diffuse Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Glossy Direct"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Glossy Indirect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Glossy Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Transmission Direct"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Transmission Indirect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Transmission Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Subsurface Direct"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Subsurface Indirect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Subsurface Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
-#ifdef WITH_CYCLES_DEBUG
- { SOCK_RGBA, 0, N_("Debug"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
-#endif
+ { SOCK_RGBA, 0, N_("Image"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_(RE_PASSNAME_Z), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, N_(RE_PASSNAME_NORMAL), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, N_(RE_PASSNAME_UV), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, N_(RE_PASSNAME_VECTOR), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_RGBA), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_DIFFUSE), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_SPEC), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_SHADOW), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_AO), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_REFLECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_REFRACT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_(RE_PASSNAME_INDEXOB), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_(RE_PASSNAME_INDEXMA), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_(RE_PASSNAME_MIST), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_EMIT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_ENVIRONMENT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_DIFFUSE_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_DIFFUSE_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_DIFFUSE_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_GLOSSY_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_GLOSSY_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_GLOSSY_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_TRANSM_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_TRANSM_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_TRANSM_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_SUBSURFACE_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_SUBSURFACE_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_SUBSURFACE_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
};
-static bNodeSocket *cmp_node_image_add_render_pass_output(bNodeTree *ntree, bNode *node, int pass, int rres_index)
+static void cmp_node_image_add_pass_output(bNodeTree *ntree, bNode *node,
+ const char *name, const char *passname,
+ int rres_index, int type, int is_rlayers,
+ LinkNodePair *available_sockets, int *prev_index)
{
bNodeSocket *sock;
- NodeImageLayer *sockdata;
-
- sock = node_add_socket_from_template(ntree, node, &cmp_node_rlayers_out[rres_index], SOCK_OUT);
- /* extra socket info */
- sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
- sock->storage = sockdata;
-
- sockdata->pass_flag = pass;
-
- return sock;
-}
-
-static void cmp_node_image_add_render_pass_outputs(bNodeTree *ntree, bNode *node, int passflag)
-{
- if (passflag & SCE_PASS_COMBINED) {
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_COMBINED, RRES_OUT_IMAGE);
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_COMBINED, RRES_OUT_ALPHA);
- }
-
- if (passflag & SCE_PASS_Z)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_Z, RRES_OUT_Z);
- if (passflag & SCE_PASS_NORMAL)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_NORMAL, RRES_OUT_NORMAL);
- if (passflag & SCE_PASS_VECTOR)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_VECTOR, RRES_OUT_VEC);
- if (passflag & SCE_PASS_UV)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_UV, RRES_OUT_UV);
- if (passflag & SCE_PASS_RGBA)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_RGBA, RRES_OUT_RGBA);
- if (passflag & SCE_PASS_DIFFUSE)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_DIFFUSE, RRES_OUT_DIFF);
- if (passflag & SCE_PASS_SPEC)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SPEC, RRES_OUT_SPEC);
- if (passflag & SCE_PASS_SHADOW)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SHADOW, RRES_OUT_SHADOW);
- if (passflag & SCE_PASS_AO)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_AO, RRES_OUT_AO);
- if (passflag & SCE_PASS_REFLECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_REFLECT, RRES_OUT_REFLECT);
- if (passflag & SCE_PASS_REFRACT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_REFRACT, RRES_OUT_REFRACT);
- if (passflag & SCE_PASS_INDIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_INDIRECT, RRES_OUT_INDIRECT);
- if (passflag & SCE_PASS_INDEXOB)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_INDEXOB, RRES_OUT_INDEXOB);
- if (passflag & SCE_PASS_INDEXMA)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_INDEXMA, RRES_OUT_INDEXMA);
- if (passflag & SCE_PASS_MIST)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_MIST, RRES_OUT_MIST);
- if (passflag & SCE_PASS_EMIT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_EMIT, RRES_OUT_EMIT);
- if (passflag & SCE_PASS_ENVIRONMENT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_ENVIRONMENT, RRES_OUT_ENV);
-
- if (passflag & SCE_PASS_DIFFUSE_DIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_DIFFUSE_DIRECT, RRES_OUT_DIFF_DIRECT);
- if (passflag & SCE_PASS_DIFFUSE_INDIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_DIFFUSE_INDIRECT, RRES_OUT_DIFF_INDIRECT);
- if (passflag & SCE_PASS_DIFFUSE_COLOR)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_DIFFUSE_COLOR, RRES_OUT_DIFF_COLOR);
-
- if (passflag & SCE_PASS_GLOSSY_DIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_GLOSSY_DIRECT, RRES_OUT_GLOSSY_DIRECT);
- if (passflag & SCE_PASS_GLOSSY_INDIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_GLOSSY_INDIRECT, RRES_OUT_GLOSSY_INDIRECT);
- if (passflag & SCE_PASS_GLOSSY_COLOR)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_GLOSSY_COLOR, RRES_OUT_GLOSSY_COLOR);
-
- if (passflag & SCE_PASS_TRANSM_DIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_TRANSM_DIRECT, RRES_OUT_TRANSM_DIRECT);
- if (passflag & SCE_PASS_TRANSM_INDIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_TRANSM_INDIRECT, RRES_OUT_TRANSM_INDIRECT);
- if (passflag & SCE_PASS_TRANSM_COLOR)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_TRANSM_COLOR, RRES_OUT_TRANSM_COLOR);
-
- if (passflag & SCE_PASS_SUBSURFACE_DIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SUBSURFACE_DIRECT, RRES_OUT_SUBSURFACE_DIRECT);
- if (passflag & SCE_PASS_SUBSURFACE_INDIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SUBSURFACE_INDIRECT, RRES_OUT_SUBSURFACE_INDIRECT);
- if (passflag & SCE_PASS_SUBSURFACE_COLOR)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SUBSURFACE_COLOR, RRES_OUT_SUBSURFACE_COLOR);
-
-#ifdef WITH_CYCLES_DEBUG
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_DEBUG, RRES_OUT_DEBUG);
-#endif
-}
-
-static void cmp_node_image_add_multilayer_outputs(bNodeTree *ntree, bNode *node, RenderLayer *rl)
-{
- bNodeSocket *sock;
- NodeImageLayer *sockdata;
- RenderPass *rpass;
- int index;
- int passflag = 0;
- for (rpass = rl->passes.first, index = 0; rpass; rpass = rpass->next, ++index) {
- int type;
- if (rpass->channels == 1)
- type = SOCK_FLOAT;
- else
- type = SOCK_RGBA;
-
- /* we only need one socket per type */
- if (passflag & rpass->passtype)
- continue;
-
- passflag |= rpass->passtype;
-
- sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, rpass->internal_name, rpass->internal_name);
+ int sock_index = BLI_findstringindex(&node->outputs, name, offsetof(bNodeSocket, name));
+
+ if (sock_index < 0) {
+ /* The first 31 sockets always are the legacy hardcoded sockets.
+ * Any dynamically allocated sockets follow afterwards, and are sorted in the order in which they were stored in the RenderResult.
+ * Therefore, we remember the index of the last matched socket. New sockets are placed behind the previously traversed one, but always after the first 31. */
+ int after_index = *prev_index;
+ if (is_rlayers && after_index < 30)
+ after_index = 30;
+
+ if (rres_index >= 0) {
+ sock = node_add_socket_from_template(ntree, node, &cmp_node_rlayers_out[rres_index], SOCK_OUT);
+ }
+ else {
+ sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, name, name);
+ }
/* extra socket info */
- sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
+ NodeImageLayer *sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
sock->storage = sockdata;
-
- sockdata->pass_index = index;
- sockdata->pass_flag = rpass->passtype;
-
- if (rpass->passtype == SCE_PASS_COMBINED) {
- sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, SOCK_FLOAT, PROP_NONE, "Alpha", "Alpha");
- sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
- sock->storage = sockdata;
- sockdata->pass_index = index;
- sockdata->pass_flag = rpass->passtype;
+
+ BLI_strncpy(sockdata->pass_name, passname, sizeof(sockdata->pass_name));
+
+ sock_index = BLI_listbase_count(&node->outputs) - 1;
+ if (sock_index != after_index + 1) {
+ bNodeSocket *after_sock = BLI_findlink(&node->outputs, after_index);
+ BLI_remlink(&node->outputs, sock);
+ BLI_insertlinkafter(&node->outputs, after_sock, sock);
+ }
+ }
+ else {
+ sock = BLI_findlink(&node->outputs, sock_index);
+ NodeImageLayer *sockdata = sock->storage;
+ if (sockdata) {
+ BLI_strncpy(sockdata->pass_name, passname, sizeof(sockdata->pass_name));
}
}
+
+ BLI_linklist_append(available_sockets, sock);
+ *prev_index = sock_index;
}
-static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node)
+static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node, LinkNodePair *available_sockets)
{
Image *ima = (Image *)node->id;
+ ImBuf *ibuf;
+ int prev_index = -1;
if (ima) {
ImageUser *iuser = node->storage;
ImageUser load_iuser = {NULL};
- ImBuf *ibuf;
int offset = BKE_image_sequence_guess_offset(ima);
/* It is possible that image user in this node is not
@@ -238,104 +154,147 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node)
RenderLayer *rl = BLI_findlink(&ima->rr->layers, iuser->layer);
if (rl) {
- if (ima->type != IMA_TYPE_MULTILAYER)
- cmp_node_image_add_render_pass_outputs(ntree, node, rl->passflag);
- else
- cmp_node_image_add_multilayer_outputs(ntree, node, rl);
+ RenderPass *rpass;
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
+ int type;
+ if (rpass->channels == 1)
+ type = SOCK_FLOAT;
+ else
+ type = SOCK_RGBA;
+
+ cmp_node_image_add_pass_output(ntree, node, rpass->name, rpass->name, -1, type, false, available_sockets, &prev_index);
+ /* Special handling for the Combined pass to ensure compatibility. */
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
+ cmp_node_image_add_pass_output(ntree, node, "Alpha", rpass->name, -1, SOCK_FLOAT, false, available_sockets, &prev_index);
+ }
+ }
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ return;
}
- else
- cmp_node_image_add_render_pass_outputs(ntree, node, RRES_OUT_IMAGE | RRES_OUT_ALPHA);
}
- else
- cmp_node_image_add_render_pass_outputs(ntree, node, RRES_OUT_IMAGE | RRES_OUT_ALPHA | RRES_OUT_Z);
-
+ }
+
+ cmp_node_image_add_pass_output(ntree, node, "Image", RE_PASSNAME_COMBINED, -1, SOCK_RGBA, false, available_sockets, &prev_index);
+ cmp_node_image_add_pass_output(ntree, node, "Alpha", RE_PASSNAME_COMBINED, -1, SOCK_FLOAT, false, available_sockets, &prev_index);
+
+ if (ima) {
+ if (!ima->rr) {
+ cmp_node_image_add_pass_output(ntree, node, RE_PASSNAME_Z, RE_PASSNAME_Z, -1, SOCK_FLOAT, false, available_sockets, &prev_index);
+ }
BKE_image_release_ibuf(ima, ibuf, NULL);
}
- else
- cmp_node_image_add_render_pass_outputs(ntree, node, RRES_OUT_IMAGE | RRES_OUT_ALPHA);
}
-static bNodeSocket *cmp_node_image_output_find_match(bNode *UNUSED(node), bNodeSocket *newsock, ListBase *oldsocklist)
-{
- bNodeSocket *sock;
-
- for (sock = oldsocklist->first; sock; sock = sock->next)
- if (STREQ(sock->name, newsock->name))
- return sock;
- return NULL;
-}
+typedef struct RLayerUpdateData {
+ LinkNodePair *available_sockets;
+ int prev_index;
+} RLayerUpdateData;
-static bNodeSocket *cmp_node_image_output_relink(bNode *node, bNodeSocket *oldsock, int oldindex)
+void node_cmp_rlayers_register_pass(bNodeTree *ntree, bNode *node, Scene *scene, SceneRenderLayer *srl, const char *name, int type)
{
- bNodeSocket *sock;
-
- /* first try to find matching socket name */
- for (sock = node->outputs.first; sock; sock = sock->next)
- if (STREQ(sock->name, oldsock->name))
- return sock;
-
- /* no matching name, simply link to same index */
- return BLI_findlink(&node->outputs, oldindex);
+ RLayerUpdateData *data = node->storage;
+
+ if (scene == NULL || srl == NULL || data == NULL || node->id != (ID *)scene) {
+ return;
+ }
+
+ SceneRenderLayer *node_srl = BLI_findlink(&scene->r.layers, node->custom1);
+ if (node_srl != srl) {
+ return;
+ }
+
+ /* Special handling for the Combined pass to ensure compatibility. */
+ if (STREQ(name, RE_PASSNAME_COMBINED)) {
+ cmp_node_image_add_pass_output(ntree, node, "Image", name, -1, type, true, data->available_sockets, &data->prev_index);
+ cmp_node_image_add_pass_output(ntree, node, "Alpha", name, -1, SOCK_FLOAT, true, data->available_sockets, &data->prev_index);
+ }
+ else {
+ cmp_node_image_add_pass_output(ntree, node, name, name, -1, type, true, data->available_sockets, &data->prev_index);
+ }
}
-static void cmp_node_image_sync_output(bNode *UNUSED(node), bNodeSocket *UNUSED(newsock), bNodeSocket *UNUSED(oldsock))
+static void cmp_node_rlayer_create_outputs(bNodeTree *ntree, bNode *node, LinkNodePair *available_sockets)
{
- /* pass */
+ Scene *scene = (Scene *)node->id;
+
+ if (scene) {
+ RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
+ if (engine_type && engine_type->update_render_passes) {
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, node->custom1);
+ if (srl) {
+ RLayerUpdateData *data = MEM_mallocN(sizeof(RLayerUpdateData), "render layer update data");
+ data->available_sockets = available_sockets;
+ data->prev_index = -1;
+ node->storage = data;
+
+ RenderEngine *engine = RE_engine_create(engine_type);
+ engine_type->update_render_passes(engine, scene, srl);
+ RE_engine_free(engine);
+
+ MEM_freeN(data);
+ node->storage = NULL;
+
+ return;
+ }
+ }
+ }
+
+ int prev_index = -1;
+ cmp_node_image_add_pass_output(ntree, node, "Image", RE_PASSNAME_COMBINED, RRES_OUT_IMAGE, SOCK_RGBA, true, available_sockets, &prev_index);
+ cmp_node_image_add_pass_output(ntree, node, "Alpha", RE_PASSNAME_COMBINED, RRES_OUT_ALPHA, SOCK_FLOAT, true, available_sockets, &prev_index);
}
/* XXX make this into a generic socket verification function for dynamic socket replacement (multilayer, groups, static templates) */
-static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node)
+static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rlayer)
{
- bNodeSocket *newsock, *oldsock, *oldsock_next;
- ListBase oldsocklist;
- int oldindex;
- bNodeLink *link;
-
- /* store current nodes in oldsocklist, then clear socket list */
- oldsocklist = node->outputs;
- BLI_listbase_clear(&node->outputs);
+ bNodeSocket *sock, *sock_next;
+ LinkNodePair available_sockets = {NULL, NULL};
+ int sock_index;
/* XXX make callback */
- cmp_node_image_create_outputs(ntree, node);
-
- for (newsock = node->outputs.first; newsock; newsock = newsock->next) {
- /* XXX make callback */
- oldsock = cmp_node_image_output_find_match(node, newsock, &oldsocklist);
- if (oldsock) {
- /* XXX make callback */
- cmp_node_image_sync_output(node, newsock, oldsock);
+ if (rlayer)
+ cmp_node_rlayer_create_outputs(ntree, node, &available_sockets);
+ else
+ cmp_node_image_create_outputs(ntree, node, &available_sockets);
+
+ /* Get rid of sockets whose passes are not available in the image.
+ * If sockets that are not available would be deleted, the connections to them would be lost
+ * when e.g. opening a file (since there's no render at all yet).
+ * Therefore, sockets with connected links will just be set as unavailable.
+ *
+ * Another important detail comes from compatibility with the older socket model, where there
+ * was a fixed socket per pass type that was just hidden or not. Therefore, older versions expect
+ * the first 31 passes to belong to a specific pass type.
+ * So, we keep those 31 always allocated before the others as well, even if they have no links attached. */
+ sock_index = 0;
+ for (sock = node->outputs.first; sock; sock = sock_next, sock_index++) {
+ sock_next = sock->next;
+ if (BLI_linklist_index(available_sockets.list, sock) >= 0) {
+ sock->flag &= ~(SOCK_UNAVAIL | SOCK_HIDDEN);
}
- }
-
- /* move links to new socket */
- for (oldsock = oldsocklist.first, oldindex = 0; oldsock; oldsock = oldsock->next, ++oldindex) {
- newsock = cmp_node_image_output_relink(node, oldsock, oldindex);
-
- if (newsock) {
+ else {
+ bNodeLink *link;
for (link = ntree->links.first; link; link = link->next) {
- if (link->fromsock == oldsock)
- link->fromsock = newsock;
+ if (link->fromsock == sock) break;
+ }
+ if (!link && (!rlayer || sock_index > 30)) {
+ MEM_freeN(sock->storage);
+ nodeRemoveSocket(ntree, node, sock);
+ }
+ else {
+ sock->flag |= SOCK_UNAVAIL;
}
}
}
-
- /* delete old sockets
- * XXX oldsock is not actually in the node->outputs list any more,
- * but the nodeRemoveSocket function works anyway. In future this
- * should become part of the core code, so can take care of this behavior.
- */
- for (oldsock = oldsocklist.first; oldsock; oldsock = oldsock_next) {
- oldsock_next = oldsock->next;
- MEM_freeN(oldsock->storage);
- nodeRemoveSocket(ntree, node, oldsock);
- }
+
+ BLI_linklist_free(available_sockets.list, NULL);
}
static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
{
/* avoid unnecessary updates, only changes to the image/image user data are of interest */
if (node->update & NODE_UPDATE_ID)
- cmp_node_image_verify_outputs(ntree, node);
+ cmp_node_image_verify_outputs(ntree, node, false);
}
static void node_composit_init_image(bNodeTree *ntree, bNode *node)
@@ -348,7 +307,7 @@ static void node_composit_init_image(bNodeTree *ntree, bNode *node)
iuser->ok = 1;
/* setup initial outputs */
- cmp_node_image_verify_outputs(ntree, node);
+ cmp_node_image_verify_outputs(ntree, node, false);
}
static void node_composit_free_image(bNode *node)
@@ -388,87 +347,44 @@ void register_node_type_cmp_image(void)
/* **************** RENDER RESULT ******************** */
-static void set_output_visible(bNode *node, int passflag, int index, int pass)
+void node_cmp_rlayers_outputs(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock = BLI_findlink(&node->outputs, index);
- bool pass_enabled = ((passflag & pass) != 0);
-#ifdef WITH_CYCLES_DEBUG
- pass_enabled |= (pass == SCE_PASS_DEBUG);
-#endif
- /* clear the SOCK_HIDDEN flag as well, in case a socket was hidden before */
- if (pass_enabled)
- sock->flag &= ~(SOCK_HIDDEN | SOCK_UNAVAIL);
- else
- sock->flag |= SOCK_UNAVAIL;
+ cmp_node_image_verify_outputs(ntree, node, true);
}
-/* clumsy checking... should do dynamic outputs once */
-void node_cmp_rlayers_force_hidden_passes(bNode *node)
+const char *node_cmp_rlayers_sock_to_pass(int sock_index)
{
- Scene *scene = (Scene *)node->id;
- SceneRenderLayer *srl;
- int passflag;
- bNodeSocket *sock;
-
- /* must always have valid scene pointer */
- if (!scene)
- return;
-
- srl = BLI_findlink(&scene->r.layers, node->custom1);
- if (!srl)
- return;
-
- passflag = srl->passflag;
-
- for (sock = node->outputs.first; sock; sock = sock->next)
- sock->flag &= ~SOCK_UNAVAIL;
-
- set_output_visible(node, passflag, RRES_OUT_IMAGE, SCE_PASS_COMBINED);
- set_output_visible(node, passflag, RRES_OUT_ALPHA, SCE_PASS_COMBINED);
-
- set_output_visible(node, passflag, RRES_OUT_Z, SCE_PASS_Z);
- set_output_visible(node, passflag, RRES_OUT_NORMAL, SCE_PASS_NORMAL);
- set_output_visible(node, passflag, RRES_OUT_VEC, SCE_PASS_VECTOR);
- set_output_visible(node, passflag, RRES_OUT_UV, SCE_PASS_UV);
- set_output_visible(node, passflag, RRES_OUT_RGBA, SCE_PASS_RGBA);
- set_output_visible(node, passflag, RRES_OUT_DIFF, SCE_PASS_DIFFUSE);
- set_output_visible(node, passflag, RRES_OUT_SPEC, SCE_PASS_SPEC);
- set_output_visible(node, passflag, RRES_OUT_SHADOW, SCE_PASS_SHADOW);
- set_output_visible(node, passflag, RRES_OUT_AO, SCE_PASS_AO);
- set_output_visible(node, passflag, RRES_OUT_REFLECT, SCE_PASS_REFLECT);
- set_output_visible(node, passflag, RRES_OUT_REFRACT, SCE_PASS_REFRACT);
- set_output_visible(node, passflag, RRES_OUT_INDIRECT, SCE_PASS_INDIRECT);
- set_output_visible(node, passflag, RRES_OUT_INDEXOB, SCE_PASS_INDEXOB);
- set_output_visible(node, passflag, RRES_OUT_INDEXMA, SCE_PASS_INDEXMA);
- set_output_visible(node, passflag, RRES_OUT_MIST, SCE_PASS_MIST);
- set_output_visible(node, passflag, RRES_OUT_EMIT, SCE_PASS_EMIT);
- set_output_visible(node, passflag, RRES_OUT_ENV, SCE_PASS_ENVIRONMENT);
- set_output_visible(node, passflag, RRES_OUT_DIFF_DIRECT, SCE_PASS_DIFFUSE_DIRECT);
- set_output_visible(node, passflag, RRES_OUT_DIFF_INDIRECT, SCE_PASS_DIFFUSE_INDIRECT);
- set_output_visible(node, passflag, RRES_OUT_DIFF_COLOR, SCE_PASS_DIFFUSE_COLOR);
- set_output_visible(node, passflag, RRES_OUT_GLOSSY_DIRECT, SCE_PASS_GLOSSY_DIRECT);
- set_output_visible(node, passflag, RRES_OUT_GLOSSY_INDIRECT, SCE_PASS_GLOSSY_INDIRECT);
- set_output_visible(node, passflag, RRES_OUT_GLOSSY_COLOR, SCE_PASS_GLOSSY_COLOR);
- set_output_visible(node, passflag, RRES_OUT_TRANSM_DIRECT, SCE_PASS_TRANSM_DIRECT);
- set_output_visible(node, passflag, RRES_OUT_TRANSM_INDIRECT, SCE_PASS_TRANSM_INDIRECT);
- set_output_visible(node, passflag, RRES_OUT_TRANSM_COLOR, SCE_PASS_TRANSM_COLOR);
- set_output_visible(node, passflag, RRES_OUT_SUBSURFACE_DIRECT, SCE_PASS_SUBSURFACE_DIRECT);
- set_output_visible(node, passflag, RRES_OUT_SUBSURFACE_INDIRECT, SCE_PASS_SUBSURFACE_INDIRECT);
- set_output_visible(node, passflag, RRES_OUT_SUBSURFACE_COLOR, SCE_PASS_SUBSURFACE_COLOR);
-
-#ifdef WITH_CYCLES_DEBUG
- set_output_visible(node, passflag, RRES_OUT_DEBUG, SCE_PASS_DEBUG);
-#endif
+ const char *sock_to_passname[] = {
+ RE_PASSNAME_COMBINED, RE_PASSNAME_COMBINED,
+ RE_PASSNAME_Z, RE_PASSNAME_NORMAL, RE_PASSNAME_UV, RE_PASSNAME_VECTOR, RE_PASSNAME_RGBA,
+ RE_PASSNAME_DIFFUSE, RE_PASSNAME_SPEC, RE_PASSNAME_SHADOW, RE_PASSNAME_AO,
+ RE_PASSNAME_REFLECT, RE_PASSNAME_REFRACT, RE_PASSNAME_INDIRECT,
+ RE_PASSNAME_INDEXOB, RE_PASSNAME_INDEXMA, RE_PASSNAME_MIST, RE_PASSNAME_EMIT, RE_PASSNAME_ENVIRONMENT,
+ RE_PASSNAME_DIFFUSE_DIRECT, RE_PASSNAME_DIFFUSE_INDIRECT, RE_PASSNAME_DIFFUSE_COLOR,
+ RE_PASSNAME_GLOSSY_DIRECT, RE_PASSNAME_GLOSSY_INDIRECT, RE_PASSNAME_GLOSSY_COLOR,
+ RE_PASSNAME_TRANSM_DIRECT, RE_PASSNAME_TRANSM_INDIRECT, RE_PASSNAME_TRANSM_COLOR,
+ RE_PASSNAME_SUBSURFACE_DIRECT, RE_PASSNAME_SUBSURFACE_INDIRECT, RE_PASSNAME_SUBSURFACE_COLOR
+ };
+ if (sock_index > 30) {
+ return NULL;
+ }
+ return sock_to_passname[sock_index];
}
static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
bNode *node = ptr->data;
-
+ int sock_index = 0;
+
node->id = &scene->id;
-
- node_cmp_rlayers_force_hidden_passes(node);
+
+ for (bNodeSocket *sock = node->outputs.first; sock; sock = sock->next, sock_index++) {
+ NodeImageLayer *sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
+ sock->storage = sockdata;
+
+ BLI_strncpy(sockdata->pass_name, node_cmp_rlayers_sock_to_pass(sock_index), sizeof(sockdata->pass_name));
+ }
}
static int node_composit_poll_rlayers(bNodeType *UNUSED(ntype), bNodeTree *ntree)
@@ -489,6 +405,29 @@ static int node_composit_poll_rlayers(bNodeType *UNUSED(ntype), bNodeTree *ntree
return false;
}
+static void node_composit_free_rlayers(bNode *node)
+{
+ bNodeSocket *sock;
+
+ /* free extra socket info */
+ for (sock = node->outputs.first; sock; sock = sock->next)
+ MEM_freeN(sock->storage);
+}
+
+static void node_composit_copy_rlayers(bNodeTree *UNUSED(dest_ntree), bNode *UNUSED(dest_node), bNode *src_node)
+{
+ bNodeSocket *sock;
+
+ /* copy extra socket info */
+ for (sock = src_node->outputs.first; sock; sock = sock->next)
+ sock->new_sock->storage = MEM_dupallocN(sock->storage);
+}
+
+static void cmp_node_rlayers_update(bNodeTree *ntree, bNode *node)
+{
+ cmp_node_image_verify_outputs(ntree, node, true);
+}
+
void register_node_type_cmp_rlayers(void)
{
static bNodeType ntype;
@@ -497,6 +436,9 @@ void register_node_type_cmp_rlayers(void)
node_type_socket_templates(&ntype, NULL, cmp_node_rlayers_out);
ntype.initfunc_api = node_composit_init_rlayers;
ntype.poll = node_composit_poll_rlayers;
+ node_type_storage(&ntype, NULL, node_composit_free_rlayers, node_composit_copy_rlayers);
+ node_type_update(&ntype, cmp_node_rlayers_update, NULL);
+ node_type_init(&ntype, node_cmp_rlayers_outputs);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
index 7d1087435c2..6a96f1b30d8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
@@ -32,7 +32,7 @@
#include <string.h>
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
+#include "BLI_string_utils.h"
#include "BKE_context.h"
diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.c b/source/blender/nodes/composite/nodes/node_composite_switchview.c
index d805cf4d87f..e0d9fa33f13 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switchview.c
+++ b/source/blender/nodes/composite/nodes/node_composite_switchview.c
@@ -137,7 +137,6 @@ static void init_switch_view(const bContext *C, PointerRNA *ptr)
cmp_node_switch_view_sanitycheck(ntree, node);
}
-/* custom1 = mix type */
void register_node_type_cmp_switch_view(void)
{
static bNodeType ntype;
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 2347564c696..0cf131adbdc 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -78,7 +78,8 @@ void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack
static void node_init_input_index(bNodeSocket *sock, int *index)
{
- if (sock->link && sock->link->fromsock) {
+ /* Only consider existing link if from socket is valid! */
+ if (sock->link && sock->link->fromsock && sock->link->fromsock->stack_index >= 0) {
sock->stack_index = sock->link->fromsock->stack_index;
}
else {
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 9bd43f331fb..5bc97f13b41 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -142,28 +142,40 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
{
memset(gs, 0, sizeof(*gs));
- nodestack_get_vec(gs->vec, type, ns);
- gs->link = ns->data;
-
- if (type == SOCK_FLOAT)
- gs->type = GPU_FLOAT;
- else if (type == SOCK_VECTOR)
- gs->type = GPU_VEC3;
- else if (type == SOCK_RGBA)
- gs->type = GPU_VEC4;
- else if (type == SOCK_SHADER)
- gs->type = GPU_VEC4;
- else
+ if (ns == NULL) {
+ /* node_get_stack() will generate NULL bNodeStack pointers for unknown/unsuported types of sockets... */
+ zero_v4(gs->vec);
+ gs->link = NULL;
gs->type = GPU_NONE;
+ gs->name = "";
+ gs->hasinput = false;
+ gs->hasoutput = false;
+ gs->sockettype = type;
+ }
+ else {
+ nodestack_get_vec(gs->vec, type, ns);
+ gs->link = ns->data;
- gs->name = "";
- gs->hasinput = ns->hasinput && ns->data;
- /* XXX Commented out the ns->data check here, as it seems it's not always set,
- * even though there *is* a valid connection/output... But that might need
- * further investigation.
- */
- gs->hasoutput = ns->hasoutput /*&& ns->data*/;
- gs->sockettype = ns->sockettype;
+ if (type == SOCK_FLOAT)
+ gs->type = GPU_FLOAT;
+ else if (type == SOCK_VECTOR)
+ gs->type = GPU_VEC3;
+ else if (type == SOCK_RGBA)
+ gs->type = GPU_VEC4;
+ else if (type == SOCK_SHADER)
+ gs->type = GPU_VEC4;
+ else
+ gs->type = GPU_NONE;
+
+ gs->name = "";
+ gs->hasinput = ns->hasinput && ns->data;
+ /* XXX Commented out the ns->data check here, as it seems it's not always set,
+ * even though there *is* a valid connection/output... But that might need
+ * further investigation.
+ */
+ gs->hasoutput = ns->hasoutput /*&& ns->data*/;
+ gs->sockettype = ns->sockettype;
+ }
}
void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
new file mode 100644
index 00000000000..e0330d110ca
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -0,0 +1,114 @@
+/*
+ * ***** 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 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_bsdf_principled_in[] = {
+ { SOCK_RGBA, 1, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Subsurface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_VECTOR, 1, N_("Subsurface Radius"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f},
+ { SOCK_RGBA, 1, N_("Subsurface Color"), 0.7f, 0.1f, 0.1f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Metallic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Specular"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Specular Tint"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Anisotropic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Anisotropic Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Sheen"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Sheen Tint"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Clearcoat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Clearcoat Roughness"), 0.03f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
+ { SOCK_FLOAT, 1, N_("Transmission"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Transmission Roughness"),0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { SOCK_VECTOR, 1, N_("Clearcoat Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { SOCK_VECTOR, 1, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_bsdf_principled_out[] = {
+ { SOCK_SHADER, 0, N_("BSDF")},
+ { -1, 0, "" }
+};
+
+static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_GLOSSY_MULTI_GGX;
+}
+
+static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ // normal
+ if (!in[17].link)
+ in[17].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[17].link, GPU_builtin(GPU_VIEW_MATRIX), &in[17].link);
+
+ // clearcoat normal
+ if (!in[18].link)
+ in[18].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[18].link, GPU_builtin(GPU_VIEW_MATRIX), &in[18].link);
+
+ return GPU_stack_link(mat, "node_bsdf_principled", in, out, GPU_builtin(GPU_VIEW_POSITION));
+}
+
+static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock;
+ int distribution = node->custom1;
+
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ if (STREQ(sock->name, "Transmission Roughness")) {
+ if (distribution == SHD_GLOSSY_GGX)
+ sock->flag &= ~SOCK_UNAVAIL;
+ else
+ sock->flag |= SOCK_UNAVAIL;
+
+ }
+ }
+}
+
+/* node type definition */
+void register_node_type_sh_bsdf_principled(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER, 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_bsdf_principled_in, sh_node_bsdf_principled_out);
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_init(&ntype, node_shader_init_principled);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_bsdf_principled);
+ node_type_update(&ntype, node_shader_update_principled, NULL);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
index ef2ce99c924..8262b70fc44 100644
--- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
@@ -51,17 +51,47 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *UNUSED(node), bNodeE
return GPU_stack_link(mat, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION));
}
+static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
+{
+ ShadeInput *shi = ((ShaderCallData *)data)->shi;
+
+ /* Compute IOR. */
+ float eta;
+ nodestack_get_vec(&eta, SOCK_FLOAT, in[0]);
+ eta = max_ff(eta, 0.00001);
+ eta = shi->flippednor ? 1 / eta : eta;
+
+ /* Get normal from socket, but only if linked. */
+ bNodeSocket *sock_normal = node->inputs.first;
+ sock_normal = sock_normal->next;
+
+ float n[3];
+ if (sock_normal->link) {
+ nodestack_get_vec(n, SOCK_VECTOR, in[1]);
+ }
+ else {
+ copy_v3_v3(n, shi->vn);
+ }
+
+ if (shi->use_world_space_shading) {
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), n);
+ }
+
+ out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, eta);
+}
+
/* node type definition */
void register_node_type_sh_fresnel(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING | NODE_OLD_SHADING);
node_type_socket_templates(&ntype, sh_node_fresnel_in, sh_node_fresnel_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_fresnel);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_fresnel);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
index 8cbc587e339..998e1a5687e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
+++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
@@ -45,23 +45,62 @@ static int node_shader_gpu_layer_weight(GPUMaterial *mat, bNode *UNUSED(node), b
{
if (!in[1].link)
in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
+ else if (GPU_material_use_world_space_shading(mat)) {
GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link);
+ }
return GPU_stack_link(mat, "node_layer_weight", in, out, GPU_builtin(GPU_VIEW_POSITION));
}
+static void node_shader_exec_layer_weight(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
+{
+ ShadeInput *shi = ((ShaderCallData *)data)->shi;
+
+ /* Compute IOR. */
+ float blend;
+ nodestack_get_vec(&blend, SOCK_FLOAT, in[0]);
+ float eta = max_ff(1 - blend, 0.00001);
+ eta = shi->flippednor ? eta : 1 / eta;
+
+ /* Get normal from socket, but only if linked. */
+ bNodeSocket *sock_normal = node->inputs.first;
+ sock_normal = sock_normal->next;
+
+ float n[3];
+ if (sock_normal->link) {
+ nodestack_get_vec(n, SOCK_VECTOR, in[1]);
+ }
+ else {
+ copy_v3_v3(n, shi->vn);
+ }
+
+
+ if (shi->use_world_space_shading)
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), n);
+
+ out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, eta);
+
+ float facing = fabs(dot_v3v3(shi->view, n));
+ if (blend != 0.5) {
+ CLAMP(blend, 0.0, 0.99999);
+ blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend);
+ facing = pow(facing, blend);
+ }
+ out[1]->vec[0] = 1.0 - facing;
+}
+
/* node type definition */
void register_node_type_sh_layer_weight(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING | NODE_OLD_SHADING);
node_type_socket_templates(&ntype, sh_node_layer_weight_in, sh_node_layer_weight_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_layer_weight);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_layer_weight);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.c b/source/blender/nodes/shader/nodes/node_shader_light_path.c
index b1001cd3937..052f2a66ec8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_light_path.c
+++ b/source/blender/nodes/shader/nodes/node_shader_light_path.c
@@ -39,6 +39,8 @@ static bNodeSocketTemplate sh_node_light_path_out[] = {
{ SOCK_FLOAT, 0, N_("Is Transmission Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Ray Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Ray Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Diffuse Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Glossy Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Transparent Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Transmission Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
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 48d1688c386..36d7522e3e6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -46,8 +46,10 @@ static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = attr;
}
-static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
- {
+static void node_shader_exec_normal_map(
+ void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata),
+ bNodeStack **in, bNodeStack **out)
+{
if (data) {
ShadeInput *shi = ((ShaderCallData *)data)->shi;
@@ -63,7 +65,7 @@ static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *n
CLAMP_MIN(strength, 0.0f);
- float *N = shi->vno;
+ float *N = shi->nmapnorm;
int uv_index = 0;
switch (nm->space) {
case SHD_NORMAL_MAP_TANGENT:
diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.c
index d1905246fd4..63d3bac88a0 100644
--- a/source/blender/nodes/shader/nodes/node_shader_object_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_object_info.c
@@ -39,7 +39,16 @@ static bNodeSocketTemplate sh_node_object_info_out[] = {
static int node_shader_gpu_object_info(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_object_info", in, out);
+ return GPU_stack_link(mat, "node_object_info", in, out, GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_OBJECT_INFO));
+}
+
+static void node_shader_exec_object_info(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out)
+{
+ ShaderCallData *scd = (ShaderCallData *)data;
+ copy_v4_v4(out[0]->vec, RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB)[3]);
+ out[1]->vec[0] = RE_object_instance_get_object_pass_index(scd->shi->obi);
+ out[2]->vec[0] = scd->shi->mat->index;
+ out[3]->vec[0] = RE_object_instance_get_random_id(scd->shi->obi) * (1.0f / (float)0xFFFFFFFF);
}
/* node type definition */
@@ -53,6 +62,7 @@ void register_node_type_sh_object_info(void)
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_object_info);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_object_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
index 0be47c4f751..1dfebc45d60 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
@@ -64,7 +64,7 @@ static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
if (STREQ(sock->name, "Mortar Smooth")) {
- ((bNodeSocketValueFloat*)sock->default_value)->value = 0.1f;
+ ((bNodeSocketValueFloat *)sock->default_value)->value = 0.1f;
}
}
}
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 359395b63c4..b694b6e994d 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -333,19 +333,14 @@ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothMo
return 1;
}
-BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, float time)
+BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s)
{
Cloth *cloth = clmd->clothObject;
ClothSimSettings *parms = clmd->sim_parms;
Implicit_Data *data = cloth->implicit;
- ClothVertex *verts = cloth->verts;
bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
- zero_v3(s->f);
- zero_m3(s->dfdx);
- zero_m3(s->dfdv);
-
s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
// calculate force of structural + shear springs
@@ -361,31 +356,13 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
if (s->type & CLOTH_SPRING_TYPE_SEWING) {
// TODO: verify, half verified (couldn't see error)
// sewing springs usually have a large distance at first so clamp the force so we don't get tunnelling through colission objects
- BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing, s->f, s->dfdx, s->dfdv);
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing);
}
else {
- BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f, s->f, s->dfdx, s->dfdv);
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f);
}
#endif
}
- else if (s->type & CLOTH_SPRING_TYPE_GOAL) {
-#ifdef CLOTH_FORCE_SPRING_GOAL
- float goal_x[3], goal_v[3];
- float k, scaling;
-
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- // current_position = xold + t * (newposition - xold)
- /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */
- interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time / parms->time_scale);
- sub_v3_v3v3(goal_v, verts[s->ij].xconst, verts[s->ij].xold); // distance covered over dt==1
-
- scaling = parms->goalspring + s->stiffness * fabsf(parms->max_struct - parms->goalspring);
- k = verts[s->ij].goal * scaling / (parms->avg_spring_len + FLT_EPSILON);
-
- BPH_mass_spring_force_spring_goal(data, s->ij, goal_x, goal_v, k, parms->goalfrict * 0.01f, s->f, s->dfdx, s->dfdv);
-#endif
- }
else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */
#ifdef CLOTH_FORCE_SPRING_BEND
float kb, cb, scaling;
@@ -398,7 +375,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
// Fix for [#45084] for cloth stiffness must have cb proportional to kb
cb = kb * parms->bending_damping;
- BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv);
+ BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb);
#endif
}
else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) {
@@ -474,9 +451,24 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
/* scale gravity force */
mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
}
+
vert = cloth->verts;
for (i = 0; i < cloth->mvert_num; i++, vert++) {
BPH_mass_spring_force_gravity(data, i, vert->mass, gravity);
+
+ /* Vertex goal springs */
+ if ((!(vert->flags & CLOTH_VERT_FLAG_PINNED)) && (vert->goal > FLT_EPSILON)) {
+ float goal_x[3], goal_v[3];
+ float k;
+
+ /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */
+ interp_v3_v3v3(goal_x, vert->xold, vert->xconst, time / clmd->sim_parms->time_scale);
+ sub_v3_v3v3(goal_v, vert->xconst, vert->xold); /* distance covered over dt==1 */
+
+ k = vert->goal * clmd->sim_parms->goalspring / (clmd->sim_parms->avg_spring_len + FLT_EPSILON);
+
+ BPH_mass_spring_force_spring_goal(data, i, goal_x, goal_v, k, clmd->sim_parms->goalfrict * 0.01f);
+ }
}
#endif
@@ -544,8 +536,9 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
for (LinkNode *link = cloth->springs; link; link = link->next) {
ClothSpring *spring = (ClothSpring *)link->link;
// only handle active springs
- if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE))
- cloth_calc_spring_force(clmd, spring, time);
+ if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE)) {
+ cloth_calc_spring_force(clmd, spring);
+ }
}
}
diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h
index d1a75ca5297..2f62ab98e12 100644
--- a/source/blender/physics/intern/implicit.h
+++ b/source/blender/physics/intern/implicit.h
@@ -114,19 +114,15 @@ void BPH_mass_spring_force_edge_wind(struct Implicit_Data *data, int v1, int v2,
void BPH_mass_spring_force_vertex_wind(struct Implicit_Data *data, int v, float radius, const float (*winvec)[3]);
/* Linear spring force between two points */
bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, int i, int j, float restlen,
- float stiffness, float damping, bool no_compress, float clamp_force,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+ float stiffness, float damping, bool no_compress, float clamp_force);
/* Bending force, forming a triangle at the base of two structural springs */
-bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int j, float restlen,
- float kb, float cb,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int j, float restlen, float kb, float cb);
/* Angular bending force based on local target vectors */
bool BPH_mass_spring_force_spring_bending_angular(struct Implicit_Data *data, int i, int j, int k,
const float target[3], float stiffness, float damping);
/* Global goal spring */
bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3],
- float stiffness, float damping,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+ float stiffness, float damping);
/* ======== Hair Volumetric Forces ======== */
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index 2ad8ee0547f..16cd335dc0c 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -1579,8 +1579,7 @@ BLI_INLINE void apply_spring(Implicit_Data *data, int i, int j, const float f[3]
}
bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, float restlen,
- float stiffness, float damping, bool no_compress, float clamp_force,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+ float stiffness, float damping, bool no_compress, float clamp_force)
{
float extent[3], length, dir[3], vel[3];
@@ -1608,25 +1607,15 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa
apply_spring(data, i, j, f, dfdx, dfdv);
- if (r_f) copy_v3_v3(r_f, f);
- if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
- if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
return true;
}
else {
- if (r_f) zero_v3(r_f);
- if (r_dfdx) zero_m3(r_dfdx);
- if (r_dfdv) zero_m3(r_dfdv);
-
return false;
}
}
/* See "Stable but Responsive Cloth" (Choi, Ko 2005) */
-bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen,
- float kb, float cb,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen, float kb, float cb)
{
float extent[3], length, dir[3], vel[3];
@@ -1646,17 +1635,9 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo
apply_spring(data, i, j, f, dfdx, dfdv);
- if (r_f) copy_v3_v3(r_f, f);
- if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
- if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
return true;
}
else {
- if (r_f) zero_v3(r_f);
- if (r_dfdx) zero_m3(r_dfdx);
- if (r_dfdv) zero_m3(r_dfdv);
-
return false;
}
}
@@ -1945,8 +1926,7 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in
}
bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3],
- float stiffness, float damping,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+ float stiffness, float damping)
{
float root_goal_x[3], root_goal_v[3], extent[3], length, dir[3], vel[3];
float f[3], dfdx[3][3], dfdv[3][3];
@@ -1973,17 +1953,9 @@ bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float g
add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfdx);
add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, dfdv);
- if (r_f) copy_v3_v3(r_f, f);
- if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
- if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
return true;
}
else {
- if (r_f) zero_v3(r_f);
- if (r_dfdx) zero_m3(r_dfdx);
- if (r_dfdv) zero_m3(r_dfdv);
-
return false;
}
}
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 3148dab3c50..b4c36a7c516 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -75,7 +75,8 @@ void BPY_thread_restore(BPy_ThreadStatePtr tstate);
bool BPY_execute_filepath(struct bContext *C, const char *filepath, struct ReportList *reports);
bool BPY_execute_text(struct bContext *C, struct Text *text, struct ReportList *reports, const bool do_jump);
-bool BPY_execute_string_as_number(struct bContext *C, const char *expr, double *value, const bool verbose);
+bool BPY_execute_string_as_number(struct bContext *C, const char *expr, const bool verbose, double *r_value);
+bool BPY_execute_string_as_string(struct bContext *C, const char *expr, const bool verbose, char **r_value);
bool BPY_execute_string_ex(struct bContext *C, const char *expr, bool use_eval);
bool BPY_execute_string(struct bContext *C, const char *expr);
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c
index 8f287918a4a..6598d402f72 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.c
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.c
@@ -44,6 +44,7 @@
#include "bmesh_py_types.h"
#include "../generic/python_utildefines.h"
+#include "../generic/py_capi_utils.h"
static int bpy_bm_op_as_py_error(BMesh *bm)
{
@@ -152,11 +153,9 @@ static int bpy_slot_from_py(
switch (slot->slot_type) {
case BMO_OP_SLOT_BOOL:
{
- int param;
+ const int param = PyC_Long_AsBool(value);
- param = PyLong_AsLong(value);
-
- if (param < 0) {
+ if (param == -1) {
PyErr_Format(PyExc_TypeError,
"%.200s: keyword \"%.200s\" expected True/False or 0/1, not %.200s",
opname, slot_name, Py_TYPE(value)->tp_name);
@@ -170,23 +169,16 @@ static int bpy_slot_from_py(
}
case BMO_OP_SLOT_INT:
{
- int overflow;
- long param = PyLong_AsLongAndOverflow(value, &overflow);
- if (overflow || (param > INT_MAX) || (param < INT_MIN)) {
- PyErr_Format(PyExc_ValueError,
- "%.200s: keyword \"%.200s\" value not in 'int' range "
- "(" STRINGIFY(INT_MIN) ", " STRINGIFY(INT_MAX) ")",
- opname, slot_name, Py_TYPE(value)->tp_name);
- return -1;
- }
- else if (param == -1 && PyErr_Occurred()) {
+ const int param = PyC_Long_AsI32(value);
+
+ if (param == -1 && PyErr_Occurred()) {
PyErr_Format(PyExc_TypeError,
"%.200s: keyword \"%.200s\" expected an int, not %.200s",
opname, slot_name, Py_TYPE(value)->tp_name);
return -1;
}
else {
- BMO_SLOT_AS_INT(slot) = (int)param;
+ BMO_SLOT_AS_INT(slot) = param;
}
break;
}
@@ -208,26 +200,19 @@ static int bpy_slot_from_py(
{
/* XXX - BMesh operator design is crappy here, operator slot should define matrix size,
* not the caller! */
- unsigned short size;
- if (!MatrixObject_Check(value)) {
- PyErr_Format(PyExc_TypeError,
- "%.200s: keyword \"%.200s\" expected a Matrix, not %.200s",
- opname, slot_name, Py_TYPE(value)->tp_name);
+ MatrixObject *pymat;
+ if (!Matrix_ParseAny(value, &pymat)) {
return -1;
}
- else if (BaseMath_ReadCallback((MatrixObject *)value) == -1) {
- return -1;
- }
- else if (((size = ((MatrixObject *)value)->num_col) != ((MatrixObject *)value)->num_row) ||
- (ELEM(size, 3, 4) == false))
- {
+ const ushort size = pymat->num_col;
+ if ((size != pymat->num_row) || (!ELEM(size, 3, 4))) {
PyErr_Format(PyExc_TypeError,
"%.200s: keyword \"%.200s\" expected a 3x3 or 4x4 matrix Matrix",
opname, slot_name);
return -1;
}
- BMO_slot_mat_set(bmop, bmop->slots_in, slot_name, ((MatrixObject *)value)->matrix, size);
+ BMO_slot_mat_set(bmop, bmop->slots_in, slot_name, pymat->matrix, size);
break;
}
case BMO_OP_SLOT_VEC:
@@ -436,7 +421,7 @@ static int bpy_slot_from_py(
return -1; /* error is set in bpy_slot_from_py_elem_check() */
}
- value_i = PyLong_AsLong(arg_value);
+ value_i = PyC_Long_AsI32(arg_value);
if (value_i == -1 && PyErr_Occurred()) {
PyErr_Format(PyExc_TypeError,
@@ -466,7 +451,7 @@ static int bpy_slot_from_py(
return -1; /* error is set in bpy_slot_from_py_elem_check() */
}
- value_i = PyLong_AsLong(arg_value);
+ value_i = PyC_Long_AsI32(arg_value);
if (value_i == -1 && PyErr_Occurred()) {
PyErr_Format(PyExc_TypeError,
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index b20c03bee28..52ca475297d 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -124,25 +124,19 @@ static int bpy_bm_elem_hflag_set(BPy_BMElem *self, PyObject *value, void *flag)
BPY_BM_CHECK_INT(self);
- param = PyLong_AsLong(value);
-
- if ((unsigned int)param <= 1) {
- if (hflag == BM_ELEM_SELECT)
- BM_elem_select_set(self->bm, self->ele, param);
- else
- BM_elem_flag_set(self->ele, hflag, param);
+ if ((param = PyC_Long_AsBool(value)) == -1) {
+ return -1;
+ }
- return 0;
+ if (hflag == BM_ELEM_SELECT) {
+ BM_elem_select_set(self->bm, self->ele, param);
}
else {
- PyErr_Format(PyExc_TypeError,
- "expected True/False or 0/1, not %.200s",
- Py_TYPE(value)->tp_name);
- return -1;
+ BM_elem_flag_set(self->ele, hflag, param);
}
+ return 0;
}
-
PyDoc_STRVAR(bpy_bm_elem_index_doc,
"Index of this element.\n"
"\n"
@@ -169,21 +163,17 @@ static int bpy_bm_elem_index_set(BPy_BMElem *self, PyObject *value, void *UNUSED
BPY_BM_CHECK_INT(self);
- param = PyLong_AsLong(value);
-
- if (param == -1 && PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError,
- "expected an int type");
+ if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) {
+ /* error is set */
return -1;
}
- else {
- BM_elem_index_set(self->ele, param); /* set_dirty! */
- /* when setting the index assume its set invalid */
- self->bm->elem_index_dirty |= self->ele->head.htype;
+ BM_elem_index_set(self->ele, param); /* set_dirty! */
- return 0;
- }
+ /* when setting the index assume its set invalid */
+ self->bm->elem_index_dirty |= self->ele->head.htype;
+
+ return 0;
}
/* type specific get/sets
@@ -506,14 +496,12 @@ static int bpy_bmface_material_index_set(BPy_BMFace *self, PyObject *value)
BPY_BM_CHECK_INT(self);
- param = PyLong_AsLong(value);
-
- if (param == -1 && PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError,
- "expected an int type");
+ if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) {
+ /* error is set */
return -1;
}
- else if ((param < 0) || (param > MAXMAT)) {
+
+ if ((param < 0) || (param > MAXMAT)) {
/* normally we clamp but in this case raise an error */
PyErr_SetString(PyExc_ValueError,
"material index outside of usable range (0 - 32766)");
@@ -1049,6 +1037,13 @@ PyDoc_STRVAR(bpy_bmesh_from_mesh_doc,
" :type use_shape_key: boolean\n"
" :arg shape_key_index: The shape key index to use.\n"
" :type shape_key_index: int\n"
+"\n"
+" .. note::\n"
+"\n"
+" Multiple calls can be used to join multiple meshes.\n"
+"\n"
+" Custom-data layers are only copied from ``mesh`` on initialization.\n"
+" Further calls will copy custom-data to matching layers, layers missing on the target mesh wont be added.\n"
);
static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
{
@@ -1113,15 +1108,16 @@ static PyObject *bpy_bmesh_select_flush(BPy_BMesh *self, PyObject *value)
BPY_BM_CHECK_OBJ(self);
- param = PyLong_AsLong(value);
- if (param != false && param != true) {
- PyErr_SetString(PyExc_TypeError,
- "expected a boolean type 0/1");
+ if ((param = PyC_Long_AsBool(value)) == -1) {
return NULL;
}
- if (param) BM_mesh_select_flush(self->bm);
- else BM_mesh_deselect_flush(self->bm);
+ if (param) {
+ BM_mesh_select_flush(self->bm);
+ }
+ else {
+ BM_mesh_deselect_flush(self->bm);
+ }
Py_RETURN_NONE;
}
@@ -1301,10 +1297,7 @@ static PyObject *bpy_bm_elem_select_set(BPy_BMElem *self, PyObject *value)
BPY_BM_CHECK_OBJ(self);
- param = PyLong_AsLong(value);
- if (param != false && param != true) {
- PyErr_SetString(PyExc_TypeError,
- "expected a boolean type 0/1");
+ if ((param = PyC_Long_AsBool(value)) == -1) {
return NULL;
}
@@ -1329,10 +1322,7 @@ static PyObject *bpy_bm_elem_hide_set(BPy_BMElem *self, PyObject *value)
BPY_BM_CHECK_OBJ(self);
- param = PyLong_AsLong(value);
- if (param != false && param != true) {
- PyErr_SetString(PyExc_TypeError,
- "expected a boolean type 0/1");
+ if ((param = PyC_Long_AsBool(value)) == -1) {
return NULL;
}
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index 908f6b5a734..cb95ded4f0d 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -43,6 +43,7 @@
#include "../mathutils/mathutils.h"
#include "../generic/python_utildefines.h"
+#include "../generic/py_capi_utils.h"
#include "BKE_customdata.h"
@@ -1074,9 +1075,9 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj
}
case CD_PROP_INT:
{
- int tmp_val = PyLong_AsLong(py_value);
+ int tmp_val = PyC_Long_AsI32(py_value);
if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) {
- PyErr_Format(PyExc_TypeError, "expected an int, not a %.200s", Py_TYPE(py_value)->tp_name);
+ /* error is set */
ret = -1;
}
else {
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
index 92c11a03433..b01d3f89d4e 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
@@ -45,6 +45,7 @@
#include "bmesh_py_types_meshdata.h"
+#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
@@ -188,7 +189,7 @@ static int bpy_bmloopuv_flag_set(BPy_BMLoopUV *self, PyObject *value, void *flag
{
const int flag = GET_INT_FROM_POINTER(flag_p);
- switch (PyLong_AsLong(value)) {
+ switch (PyC_Long_AsBool(value)) {
case true:
self->data->flag |= flag;
return 0;
@@ -196,8 +197,7 @@ static int bpy_bmloopuv_flag_set(BPy_BMLoopUV *self, PyObject *value, void *flag
self->data->flag &= ~flag;
return 0;
default:
- PyErr_SetString(PyExc_TypeError,
- "expected a boolean type 0/1");
+ /* error is set */
return -1;
}
}
@@ -297,7 +297,7 @@ static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void *
{
const int flag = GET_INT_FROM_POINTER(flag_p);
- switch (PyLong_AsLong(value)) {
+ switch (PyC_Long_AsBool(value)) {
case true:
self->data->flag |= flag;
return 0;
@@ -305,8 +305,7 @@ static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void *
self->data->flag &= ~flag;
return 0;
default:
- PyErr_SetString(PyExc_TypeError,
- "expected a boolean type 0/1");
+ /* error is set */
return -1;
}
}
diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c
index 89c196dbcad..fc0cd9e475b 100644
--- a/source/blender/python/bmesh/bmesh_py_utils.c
+++ b/source/blender/python/bmesh/bmesh_py_utils.c
@@ -565,6 +565,10 @@ PyDoc_STRVAR(bpy_bm_utils_face_split_edgenet_doc,
" :type edgenet: :class:`bmesh.types.BMEdge`\n"
" :return: The newly created faces.\n"
" :rtype: tuple of (:class:`bmesh.types.BMFace`)\n"
+"\n"
+" .. note::\n"
+"\n"
+" Regions defined by edges need to connect to the face, otherwise they're ignored as loose edges.\n"
);
static PyObject *bpy_bm_utils_face_split_edgenet(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index 3ea10228ad4..a0185b0f4fa 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -472,6 +472,49 @@ int BGL_typeSize(int type)
return -1;
}
+static int gl_buffer_type_from_py_format_char(char *typestr)
+{
+ if (ELEM(typestr[0], '<', '>', '|')) {
+ typestr += 1;
+ }
+ char format = typestr[0];
+ char byte_num = typestr[1];
+
+ switch (format) {
+ case 't':
+ case 'b':
+ case 'h':
+ if (!byte_num) return GL_BYTE;
+ ATTR_FALLTHROUGH;
+ case 'i':
+ if (!byte_num) return GL_SHORT;
+ ATTR_FALLTHROUGH;
+ case 'l':
+ if (!byte_num || byte_num == '4') return GL_INT;
+ if (byte_num == '1') return GL_BYTE;
+ if (byte_num == '2') return GL_SHORT;
+ break;
+ case 'f':
+ if (!byte_num) return GL_FLOAT;
+ ATTR_FALLTHROUGH;
+ case 'd':
+ if (!byte_num || byte_num == '8') return GL_DOUBLE;
+ if (byte_num == '4') return GL_FLOAT;
+ break;
+ }
+ return -1; /* UNKNOWN */
+}
+
+static bool compare_dimensions(int ndim, int *dim1, Py_ssize_t *dim2)
+{
+ for (int i = 0; i < ndim; i++) {
+ if (dim1[i] != dim2[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
/** \} */
@@ -630,6 +673,22 @@ PyTypeObject BGL_bufferType = {
NULL /*tp_del*/
};
+
+static Buffer *BGL_MakeBuffer_FromData(PyObject *parent, int type, int ndimensions, int *dimensions, void *buf)
+{
+ Buffer *buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType);
+
+ Py_XINCREF(parent);
+ buffer->parent = parent;
+ buffer->ndimensions = ndimensions;
+ buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions");
+ memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int));
+ buffer->type = type;
+ buffer->buf.asvoid = buf;
+
+ return buffer;
+}
+
/**
* Create a buffer object
*
@@ -641,30 +700,21 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf
{
Buffer *buffer;
void *buf = NULL;
- int i, size, length;
+ int i, size = BGL_typeSize(type);
- length = 1;
for (i = 0; i < ndimensions; i++) {
- length *= dimensions[i];
+ size *= dimensions[i];
}
- size = BGL_typeSize(type);
+ buf = MEM_mallocN(size, "Buffer buffer");
- buf = MEM_mallocN(length * size, "Buffer buffer");
-
- buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType);
- buffer->parent = NULL;
- buffer->ndimensions = ndimensions;
- buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions");
- memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int));
- buffer->type = type;
- buffer->buf.asvoid = buf;
+ buffer = BGL_MakeBuffer_FromData(NULL, type, ndimensions, dimensions, buf);
if (initbuffer) {
- memcpy(buffer->buf.asvoid, initbuffer, length * size);
+ memcpy(buffer->buf.asvoid, initbuffer, size);
}
else {
- memset(buffer->buf.asvoid, 0, length * size);
+ memset(buffer->buf.asvoid, 0, size);
}
return buffer;
}
@@ -674,7 +724,7 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf
static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
{
PyObject *length_ob = NULL, *init = NULL;
- Buffer *buffer;
+ Buffer *buffer = NULL;
int dimensions[MAX_DIMENSIONS];
int type;
@@ -739,9 +789,32 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject
return NULL;
}
- buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL);
- if (init && ndimensions) {
- if (Buffer_ass_slice(buffer, 0, dimensions[0], init)) {
+ if (init && PyObject_CheckBuffer(init)) {
+ Py_buffer pybuffer;
+
+ if (PyObject_GetBuffer(init, &pybuffer, PyBUF_ND | PyBUF_FORMAT) == -1) {
+ /* PyObject_GetBuffer raise a PyExc_BufferError */
+ return NULL;
+ }
+
+ if (type != gl_buffer_type_from_py_format_char(pybuffer.format)) {
+ PyErr_Format(PyExc_TypeError,
+ "`GL_TYPE` and `typestr` of object with buffer interface do not match. '%s'", pybuffer.format);
+ }
+ else if (ndimensions != pybuffer.ndim ||
+ !compare_dimensions(ndimensions, dimensions, pybuffer.shape))
+ {
+ PyErr_Format(PyExc_TypeError, "array size does not match");
+ }
+ else {
+ buffer = BGL_MakeBuffer_FromData(init, type, pybuffer.ndim, dimensions, pybuffer.buf);
+ }
+
+ PyBuffer_Release(&pybuffer);
+ }
+ else {
+ buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL);
+ if (init && Buffer_ass_slice(buffer, 0, dimensions[0], init)) {
Py_DECREF(buffer);
return NULL;
}
@@ -774,27 +847,17 @@ static PyObject *Buffer_item(Buffer *self, int i)
}
}
else {
- Buffer *newbuf;
- int j, length, size;
+ int j, offset = i * BGL_typeSize(self->type);
- length = 1;
for (j = 1; j < self->ndimensions; j++) {
- length *= self->dimensions[j];
+ offset *= self->dimensions[j];
}
- size = BGL_typeSize(self->type);
-
- newbuf = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType);
-
- Py_INCREF(self);
- newbuf->parent = (PyObject *)self;
-
- newbuf->ndimensions = self->ndimensions - 1;
- newbuf->type = self->type;
- newbuf->buf.asvoid = self->buf.asbyte + i * length * size;
- newbuf->dimensions = MEM_mallocN(newbuf->ndimensions * sizeof(int), "Buffer dimensions");
- memcpy(newbuf->dimensions, self->dimensions + 1, newbuf->ndimensions * sizeof(int));
- return (PyObject *)newbuf;
+ return (PyObject *)BGL_MakeBuffer_FromData(
+ (PyObject *)self, self->type,
+ self->ndimensions - 1,
+ self->dimensions + 1,
+ self->buf.asbyte + offset);
}
return NULL;
diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c
index ed2752d8372..ffac09efdde 100644
--- a/source/blender/python/generic/bpy_internal_import.c
+++ b/source/blender/python/generic/bpy_internal_import.c
@@ -248,8 +248,17 @@ PyObject *bpy_text_reimport(PyObject *module, int *found)
if ((name = PyModule_GetName(module)) == NULL)
return NULL;
- if ((filepath = (char *)PyModule_GetFilename(module)) == NULL)
- return NULL;
+ {
+ PyObject *module_file = PyModule_GetFilenameObject(module);
+ if (module_file == NULL) {
+ return NULL;
+ }
+ filepath = _PyUnicode_AsString(module_file);
+ Py_DECREF(module_file);
+ if (filepath == NULL) {
+ return NULL;
+ }
+ }
/* look up the text object */
text = BLI_findstring(&maggie->text, BLI_path_basename(filepath), offsetof(ID, name) + 2);
@@ -276,13 +285,13 @@ static PyObject *blender_import(PyObject *UNUSED(self), PyObject *args, PyObject
int found = 0;
PyObject *globals = NULL, *locals = NULL, *fromlist = NULL;
int level = 0; /* relative imports */
-
PyObject *newmodule;
- //PyObject_Print(args, stderr, 0);
- static const char *kwlist[] = {"name", "globals", "locals", "fromlist", "level", NULL};
-
- if (!PyArg_ParseTupleAndKeywords(args, kw, "s|OOOi:bpy_import_meth", (char **)kwlist,
- &name, &globals, &locals, &fromlist, &level))
+
+ static const char *_keywords[] = {"name", "globals", "locals", "fromlist", "level", NULL};
+ static _PyArg_Parser _parser = {"s|OOOi:bpy_import_meth", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &name, &globals, &locals, &fromlist, &level))
{
return NULL;
}
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 2e15b7b1413..1153e0176df 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -43,6 +43,9 @@
#include "python_utildefines.h"
+extern bool pyrna_id_FromPyObject(PyObject *obj, ID **id);
+extern PyObject *pyrna_id_CreatePyObject(ID *id);
+extern bool pyrna_id_CheckPyObject(PyObject *obj);
/*********************** ID Property Main Wrapper Stuff ***************/
@@ -88,6 +91,11 @@ static PyObject *idprop_py_from_idp_group(ID *id, IDProperty *prop, IDProperty *
return (PyObject *)group;
}
+static PyObject *idprop_py_from_idp_id(IDProperty *prop)
+{
+ return pyrna_id_CreatePyObject(prop->data.pointer);
+}
+
static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop)
{
BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &BPy_IDArray_Type);
@@ -148,6 +156,7 @@ PyObject *BPy_IDGroup_WrapData(ID *id, IDProperty *prop, IDProperty *parent)
case IDP_GROUP: return idprop_py_from_idp_group(id, prop, parent);
case IDP_ARRAY: return idprop_py_from_idp_array(id, prop);
case IDP_IDPARRAY: return idprop_py_from_idp_idparray(id, prop); /* this could be better a internal type */
+ case IDP_ID: return idprop_py_from_idp_id(prop);
default: Py_RETURN_NONE;
}
}
@@ -335,19 +344,9 @@ static char idp_sequence_type(PyObject *seq_fast)
return type;
}
-/**
- * \note group can be a pointer array or a group.
- * assume we already checked key is a string.
- *
- * \return success.
- */
-bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
+static const char *idp_try_read_name(PyObject *name_obj)
{
- IDProperty *prop = NULL;
- IDPropertyTemplate val = {0};
-
- const char *name;
-
+ const char *name = NULL;
if (name_obj) {
Py_ssize_t name_size;
name = _PyUnicode_AsStringAndSize(name_obj, &name_size);
@@ -356,168 +355,307 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
PyErr_Format(PyExc_KeyError,
"invalid id-property key, expected a string, not a %.200s",
Py_TYPE(name_obj)->tp_name);
- return false;
+ return NULL;
}
if (name_size > MAX_IDPROP_NAME) {
PyErr_SetString(PyExc_KeyError, "the length of IDProperty names is limited to 63 characters");
- return false;
+ return NULL;
}
}
else {
name = "";
}
+ return name;
+}
- if (PyFloat_Check(ob)) {
- val.d = PyFloat_AsDouble(ob);
- prop = IDP_New(IDP_DOUBLE, &val, name);
- }
- else if (PyLong_Check(ob)) {
- val.i = _PyLong_AsInt(ob);
- if (val.i == -1 && PyErr_Occurred()) {
- return false;
- }
- prop = IDP_New(IDP_INT, &val, name);
+/* -------------------------------------------------------------------------- */
+
+/**
+ * The 'idp_from_Py*' functions expect that the input type has been checked before
+ * and return NULL if the IDProperty can't be created.
+ */
+
+static IDProperty *idp_from_PyFloat(const char *name, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ val.d = PyFloat_AsDouble(ob);
+ return IDP_New(IDP_DOUBLE, &val, name);
+}
+
+static IDProperty *idp_from_PyLong(const char *name, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ val.i = PyC_Long_AsI32(ob);
+ if (val.i == -1 && PyErr_Occurred()) {
+ return NULL;
}
- else if (PyUnicode_Check(ob)) {
+ return IDP_New(IDP_INT, &val, name);
+}
+
+static IDProperty *idp_from_PyUnicode(const char *name, PyObject *ob)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
#ifdef USE_STRING_COERCE
- Py_ssize_t value_size;
- PyObject *value_coerce = NULL;
- val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce);
- val.string.len = (int)value_size + 1;
- val.string.subtype = IDP_STRING_SUB_UTF8;
- prop = IDP_New(IDP_STRING, &val, name);
- Py_XDECREF(value_coerce);
+ Py_ssize_t value_size;
+ PyObject *value_coerce = NULL;
+ val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce);
+ val.string.len = (int)value_size + 1;
+ val.string.subtype = IDP_STRING_SUB_UTF8;
+ prop = IDP_New(IDP_STRING, &val, name);
+ Py_XDECREF(value_coerce);
#else
- val.str = _PyUnicode_AsString(ob);
- prop = IDP_New(IDP_STRING, val, name);
+ val.str = _PyUnicode_AsString(ob);
+ prop = IDP_New(IDP_STRING, val, name);
#endif
- }
- else if (PyBytes_Check(ob)) {
- val.string.str = PyBytes_AS_STRING(ob);
- val.string.len = PyBytes_GET_SIZE(ob);
- val.string.subtype = IDP_STRING_SUB_BYTE;
+ return prop;
+}
+
+static IDProperty *idp_from_PyBytes(const char *name, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ val.string.str = PyBytes_AS_STRING(ob);
+ val.string.len = PyBytes_GET_SIZE(ob);
+ val.string.subtype = IDP_STRING_SUB_BYTE;
+ return IDP_New(IDP_STRING, &val, name);
+}
- prop = IDP_New(IDP_STRING, &val, name);
- //prop = IDP_NewString(PyBytes_AS_STRING(ob), name, PyBytes_GET_SIZE(ob));
- //prop->subtype = IDP_STRING_SUB_BYTE;
+static int idp_array_type_from_format_char(char format)
+{
+ if (format == 'i') return IDP_INT;
+ if (format == 'f') return IDP_FLOAT;
+ if (format == 'd') return IDP_DOUBLE;
+ return -1;
+}
+
+static const char *idp_format_from_array_type(int type)
+{
+ if (type == IDP_INT) return "i";
+ if (type == IDP_FLOAT) return "f";
+ if (type == IDP_DOUBLE) return "d";
+ return NULL;
+}
+
+static IDProperty *idp_from_PySequence_Buffer(const char *name, Py_buffer *buffer)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
+
+ int format = idp_array_type_from_format_char(*buffer->format);
+ if (format == -1) {
+ /* should never happen as the type has been checked before */
+ return NULL;
}
- else if (PySequence_Check(ob)) {
- PyObject *ob_seq_fast;
- PyObject **ob_seq_fast_items;
- PyObject *item;
- int i;
+ else {
+ val.array.type = format;
+ val.array.len = buffer->len / buffer->itemsize;
+ }
+ prop = IDP_New(IDP_ARRAY, &val, name);
+ memcpy(IDP_Array(prop), buffer->buf, buffer->len);
+ return prop;
+}
- if (!(ob_seq_fast = PySequence_Fast(ob, "py -> idprop"))) {
- return false;
- }
+static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
- ob_seq_fast_items = PySequence_Fast_ITEMS(ob_seq_fast);
+ PyObject **ob_seq_fast_items;
+ PyObject *item;
+ int i;
- if ((val.array.type = idp_sequence_type(ob_seq_fast)) == (char)-1) {
- Py_DECREF(ob_seq_fast);
- PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays");
- return false;
- }
+ ob_seq_fast_items = PySequence_Fast_ITEMS(ob);
- /* validate sequence and derive type.
- * we assume IDP_INT unless we hit a float
- * number; then we assume it's */
+ if ((val.array.type = idp_sequence_type(ob)) == (char)-1) {
+ PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays");
+ return NULL;
+ }
- val.array.len = PySequence_Fast_GET_SIZE(ob_seq_fast);
+ /* validate sequence and derive type.
+ * we assume IDP_INT unless we hit a float
+ * number; then we assume it's */
- switch (val.array.type) {
- case IDP_DOUBLE:
- {
- double *prop_data;
-
- prop = IDP_New(IDP_ARRAY, &val, name);
- prop_data = IDP_Array(prop);
- for (i = 0; i < val.array.len; i++) {
- item = ob_seq_fast_items[i];
- if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) {
- Py_DECREF(ob_seq_fast);
- return false;
- }
+ val.array.len = PySequence_Fast_GET_SIZE(ob);
+
+ switch (val.array.type) {
+ case IDP_DOUBLE:
+ {
+ double *prop_data;
+ prop = IDP_New(IDP_ARRAY, &val, name);
+ prop_data = IDP_Array(prop);
+ for (i = 0; i < val.array.len; i++) {
+ item = ob_seq_fast_items[i];
+ if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) {
+ return NULL;
}
- break;
}
- case IDP_INT:
- {
- int *prop_data;
- prop = IDP_New(IDP_ARRAY, &val, name);
- prop_data = IDP_Array(prop);
- for (i = 0; i < val.array.len; i++) {
- item = ob_seq_fast_items[i];
- if (((prop_data[i] = _PyLong_AsInt(item)) == -1) && PyErr_Occurred()) {
- Py_DECREF(ob_seq_fast);
- return false;
- }
+ break;
+ }
+ case IDP_INT:
+ {
+ int *prop_data;
+ prop = IDP_New(IDP_ARRAY, &val, name);
+ prop_data = IDP_Array(prop);
+ for (i = 0; i < val.array.len; i++) {
+ item = ob_seq_fast_items[i];
+ if (((prop_data[i] = PyC_Long_AsI32(item)) == -1) && PyErr_Occurred()) {
+ return NULL;
}
- break;
}
- case IDP_IDPARRAY:
- {
- prop = IDP_NewIDPArray(name);
- for (i = 0; i < val.array.len; i++) {
- item = ob_seq_fast_items[i];
-
- if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) {
- Py_DECREF(ob_seq_fast);
- return false;
- }
+ break;
+ }
+ case IDP_IDPARRAY:
+ {
+ prop = IDP_NewIDPArray(name);
+ for (i = 0; i < val.array.len; i++) {
+ item = ob_seq_fast_items[i];
+ if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) {
+ return NULL;
}
- break;
}
- default:
- /* should never happen */
- Py_DECREF(ob_seq_fast);
- PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type");
- return false;
+ break;
}
+ default:
+ /* should never happen */
+ PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type");
+ return NULL;
+ }
+ return prop;
+}
- Py_DECREF(ob_seq_fast);
+
+static IDProperty *idp_from_PySequence(const char *name, PyObject *ob)
+{
+ Py_buffer buffer;
+ bool use_buffer = false;
+
+ if (PyObject_CheckBuffer(ob)) {
+ PyObject_GetBuffer(ob, &buffer, PyBUF_SIMPLE | PyBUF_FORMAT);
+ char format = *buffer.format;
+ if (ELEM(format, 'i', 'f', 'd')) {
+ use_buffer = true;
+ }
+ else {
+ PyBuffer_Release(&buffer);
+ }
}
- else if (PyMapping_Check(ob)) {
- PyObject *keys, *vals, *key, *pval;
- int i, len;
- /*yay! we get into recursive stuff now!*/
- keys = PyMapping_Keys(ob);
- vals = PyMapping_Values(ob);
-
- /* we allocate the group first; if we hit any invalid data,
- * we can delete it easily enough.*/
- prop = IDP_New(IDP_GROUP, &val, name);
- len = PyMapping_Length(ob);
- for (i = 0; i < len; i++) {
- key = PySequence_GetItem(keys, i);
- pval = PySequence_GetItem(vals, i);
- if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) {
- IDP_FreeProperty(prop);
- MEM_freeN(prop);
- Py_XDECREF(keys);
- Py_XDECREF(vals);
- Py_XDECREF(key);
- Py_XDECREF(pval);
- /* error is already set */
- return false;
- }
+
+ if (use_buffer) {
+ IDProperty *prop = idp_from_PySequence_Buffer(name, &buffer);
+ PyBuffer_Release(&buffer);
+ return prop;
+ }
+ else {
+ PyObject *ob_seq_fast = PySequence_Fast(ob, "py -> idprop");
+ if (ob_seq_fast != NULL) {
+ IDProperty *prop = idp_from_PySequence_Fast(name, ob_seq_fast);
+ Py_DECREF(ob_seq_fast);
+ return prop;
+ }
+ else {
+ return NULL;
+ }
+ }
+}
+
+static IDProperty *idp_from_PyMapping(const char *name, PyObject *ob)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
+
+ PyObject *keys, *vals, *key, *pval;
+ int i, len;
+ /* yay! we get into recursive stuff now! */
+ keys = PyMapping_Keys(ob);
+ vals = PyMapping_Values(ob);
+
+ /* we allocate the group first; if we hit any invalid data,
+ * we can delete it easily enough.*/
+ prop = IDP_New(IDP_GROUP, &val, name);
+ len = PyMapping_Length(ob);
+ for (i = 0; i < len; i++) {
+ key = PySequence_GetItem(keys, i);
+ pval = PySequence_GetItem(vals, i);
+ if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) {
+ IDP_FreeProperty(prop);
+ MEM_freeN(prop);
+ Py_XDECREF(keys);
+ Py_XDECREF(vals);
Py_XDECREF(key);
Py_XDECREF(pval);
+ /* error is already set */
+ return NULL;
}
- Py_XDECREF(keys);
- Py_XDECREF(vals);
+ Py_XDECREF(key);
+ Py_XDECREF(pval);
+ }
+ Py_XDECREF(keys);
+ Py_XDECREF(vals);
+ return prop;
+}
+
+static IDProperty *idp_from_DatablockPointer(const char *name, PyObject *ob, IDPropertyTemplate *val)
+{
+ pyrna_id_FromPyObject(ob, &val->id);
+ return IDP_New(IDP_ID, val, name);
+}
+
+static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ const char *name = idp_try_read_name(name_obj);
+ if (name == NULL) {
+ return NULL;
+ }
+
+ if (PyFloat_Check(ob)) {
+ return idp_from_PyFloat(name, ob);
+ }
+ else if (PyLong_Check(ob)) {
+ return idp_from_PyLong(name, ob);
+ }
+ else if (PyUnicode_Check(ob)) {
+ return idp_from_PyUnicode(name, ob);
+ }
+ else if (PyBytes_Check(ob)) {
+ return idp_from_PyBytes(name, ob);
+ }
+ else if (PySequence_Check(ob)) {
+ return idp_from_PySequence(name, ob);
+ }
+ else if (ob == Py_None || pyrna_id_CheckPyObject(ob)) {
+ return idp_from_DatablockPointer(name, ob, &val);
+ }
+ else if (PyMapping_Check(ob)) {
+ return idp_from_PyMapping(name, ob);
}
else {
PyErr_Format(PyExc_TypeError,
"invalid id-property type %.200s not supported",
Py_TYPE(ob)->tp_name);
+ return NULL;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * \note group can be a pointer array or a group.
+ * assume we already checked key is a string.
+ *
+ * \return success.
+ */
+bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
+{
+ IDProperty *prop = idp_from_PyObject(name_obj, ob);
+ if (prop == NULL) {
return false;
}
if (group->type == IDP_IDPARRAY) {
IDP_AppendArray(group, prop);
- // IDP_FreeProperty(item); /* IDP_AppendArray does a shallow copy (memcpy), only free memory */
+ /* IDP_AppendArray does a shallow copy (memcpy), only free memory */
MEM_freeN(prop);
}
else {
@@ -613,6 +751,8 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
return idprop_py_from_idp_float(prop);
case IDP_DOUBLE:
return idprop_py_from_idp_double(prop);
+ case IDP_ID:
+ return idprop_py_from_idp_id(prop);
case IDP_ARRAY:
{
PyObject *seq = PyList_New(prop->len);
@@ -1197,7 +1337,7 @@ static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
}
case IDP_INT:
{
- const int i = _PyLong_AsInt(value);
+ const int i = PyC_Long_AsI32(value);
if (i == -1 && PyErr_Occurred()) {
return -1;
}
@@ -1371,6 +1511,44 @@ static PyMappingMethods BPy_IDArray_AsMapping = {
(objobjargproc)BPy_IDArray_ass_subscript
};
+static int itemsize_by_idarray_type(int array_type)
+{
+ if (array_type == IDP_INT) return sizeof(int);
+ if (array_type == IDP_FLOAT) return sizeof(float);
+ if (array_type == IDP_DOUBLE) return sizeof(double);
+ return -1; /* should never happen */
+}
+
+static int BPy_IDArray_getbuffer(BPy_IDArray *self, Py_buffer *view, int flags)
+{
+ IDProperty *prop = self->prop;
+ int itemsize = itemsize_by_idarray_type(prop->subtype);
+ int length = itemsize * prop->len;
+
+ if (PyBuffer_FillInfo(view, (PyObject *)self, IDP_Array(prop), length, false, flags) == -1) {
+ return -1;
+ }
+
+ view->itemsize = itemsize;
+ view->format = (char *)idp_format_from_array_type(prop->subtype);
+
+ Py_ssize_t *shape = MEM_mallocN(sizeof(Py_ssize_t), __func__);
+ shape[0] = prop->len;
+ view->shape = shape;
+
+ return 0;
+}
+
+static void BPy_IDArray_releasebuffer(BPy_IDArray *UNUSED(self), Py_buffer *view)
+{
+ MEM_freeN(view->shape);
+}
+
+static PyBufferProcs BPy_IDArray_Buffer = {
+ (getbufferproc)BPy_IDArray_getbuffer,
+ (releasebufferproc)BPy_IDArray_releasebuffer,
+};
+
PyTypeObject BPy_IDArray_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -1403,7 +1581,7 @@ PyTypeObject BPy_IDArray_Type = {
NULL, /* setattrofunc tp_setattro; */
/* Functions to access object as input/output buffer */
- NULL, /* PyBufferProcs *tp_as_buffer; */
+ &BPy_IDArray_Buffer, /* PyBufferProcs *tp_as_buffer; */
/*** Flags to define presence of optional/expanded features ***/
Py_TPFLAGS_DEFAULT, /* long tp_flags; */
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 7b2d58a1268..d49f9514b8c 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -85,7 +85,7 @@ int PyC_AsArray_FAST(
/* could use is_double for 'long int' but no use now */
int *array_int = array;
for (i = 0; i < length; i++) {
- array_int[i] = PyLong_AsLong(value_fast_items[i]);
+ array_int[i] = PyC_Long_AsI32(value_fast_items[i]);
}
}
else if (type == &PyBool_Type) {
@@ -127,54 +127,52 @@ int PyC_AsArray(
return ret;
}
+/* -------------------------------------------------------------------- */
+/** \name Typed Tuple Packing
+ *
+ * \note See #PyC_Tuple_Pack_* macros that take multiple arguments.
+ *
+ * \{ */
+
/* array utility function */
-PyObject *PyC_FromArray(const void *array, int length, const PyTypeObject *type,
- const bool is_double, const char *error_prefix)
+PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len)
{
- PyObject *tuple;
- int i;
-
- tuple = PyTuple_New(length);
-
- /* for each type */
- if (type == &PyFloat_Type) {
- if (is_double) {
- const double *array_double = array;
- for (i = 0; i < length; ++i) {
- PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_double[i]));
- }
- }
- else {
- const float *array_float = array;
- for (i = 0; i < length; ++i) {
- PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_float[i]));
- }
- }
- }
- else if (type == &PyLong_Type) {
- /* could use is_double for 'long int' but no use now */
- const int *array_int = array;
- for (i = 0; i < length; ++i) {
- PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array_int[i]));
- }
+ PyObject *tuple = PyTuple_New(len);
+ for (uint i = 0; i < len; i++) {
+ PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array[i]));
}
- else if (type == &PyBool_Type) {
- const int *array_bool = array;
- for (i = 0; i < length; ++i) {
- PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array_bool[i]));
- }
+ return tuple;
+}
+
+PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len)
+{
+ PyObject *tuple = PyTuple_New(len);
+ for (uint i = 0; i < len; i++) {
+ PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array[i]));
}
- else {
- Py_DECREF(tuple);
- PyErr_Format(PyExc_TypeError,
- "%s: internal error %s is invalid",
- error_prefix, type->tp_name);
- return NULL;
+ return tuple;
+}
+
+PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len)
+{
+ PyObject *tuple = PyTuple_New(len);
+ for (uint i = 0; i < len; i++) {
+ PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i]));
}
+ return tuple;
+}
+PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len)
+{
+ PyObject *tuple = PyTuple_New(len);
+ for (uint i = 0; i < len; i++) {
+ PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i]));
+ }
return tuple;
}
+/** \} */
+
/**
* Caller needs to ensure tuple is uninitialized.
* Handy for filling a tuple with None for eg.
@@ -203,6 +201,8 @@ void PyC_List_Fill(PyObject *list, PyObject *value)
/**
* Use with PyArg_ParseTuple's "O&" formatting.
+ *
+ * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing.
*/
int PyC_ParseBool(PyObject *o, void *p)
{
@@ -300,7 +300,14 @@ void PyC_FileAndNum(const char **filename, int *lineno)
if (mod_name) {
PyObject *mod = PyDict_GetItem(PyImport_GetModuleDict(), mod_name);
if (mod) {
- *filename = PyModule_GetFilename(mod);
+ PyObject *mod_file = PyModule_GetFilenameObject(mod);
+ if (mod_file) {
+ *filename = _PyUnicode_AsString(mod_name);
+ Py_DECREF(mod_file);
+ }
+ else {
+ PyErr_Clear();
+ }
}
/* unlikely, fallback */
@@ -918,11 +925,11 @@ char *PyC_FlagSet_AsString(PyC_FlagSet *item)
return cstring;
}
-int PyC_FlagSet_ValueFromID_int(PyC_FlagSet *item, const char *identifier, int *value)
+int PyC_FlagSet_ValueFromID_int(PyC_FlagSet *item, const char *identifier, int *r_value)
{
for ( ; item->identifier; item++) {
if (STREQ(item->identifier, identifier)) {
- *value = item->value;
+ *r_value = item->value;
return 1;
}
}
@@ -930,9 +937,9 @@ int PyC_FlagSet_ValueFromID_int(PyC_FlagSet *item, const char *identifier, int *
return 0;
}
-int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int *value, const char *error_prefix)
+int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int *r_value, const char *error_prefix)
{
- if (PyC_FlagSet_ValueFromID_int(item, identifier, value) == 0) {
+ if (PyC_FlagSet_ValueFromID_int(item, identifier, r_value) == 0) {
const char *enum_str = PyC_FlagSet_AsString(item);
PyErr_Format(PyExc_ValueError,
"%s: '%.200s' not found in (%s)",
@@ -1006,7 +1013,7 @@ PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag)
*
* \note it is caller's responsibility to acquire & release GIL!
*/
-bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filename)
+bool PyC_RunString_AsNumber(const char *expr, const char *filename, double *r_value)
{
PyObject *py_dict, *mod, *retval;
bool ok = true;
@@ -1058,11 +1065,48 @@ bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filenam
ok = false;
}
else if (!isfinite(val)) {
- *value = 0.0;
+ *r_value = 0.0;
+ }
+ else {
+ *r_value = val;
+ }
+ }
+
+ PyC_MainModule_Restore(main_mod);
+
+ return ok;
+}
+
+bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_value)
+{
+ PyObject *py_dict, *retval;
+ bool ok = true;
+ PyObject *main_mod = NULL;
+
+ PyC_MainModule_Backup(&main_mod);
+
+ py_dict = PyC_DefaultNameSpace(filename);
+
+ retval = PyRun_String(expr, Py_eval_input, py_dict, py_dict);
+
+ if (retval == NULL) {
+ ok = false;
+ }
+ else {
+ const char *val;
+ Py_ssize_t val_len;
+
+ val = _PyUnicode_AsStringAndSize(retval, &val_len);
+ if (val == NULL && PyErr_Occurred()) {
+ ok = false;
}
else {
- *value = val;
+ char *val_alloc = MEM_mallocN(val_len + 1, __func__);
+ memcpy(val_alloc, val, val_len + 1);
+ *r_value = val_alloc;
}
+
+ Py_DECREF(retval);
}
PyC_MainModule_Restore(main_mod);
@@ -1071,3 +1115,101 @@ bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filenam
}
#endif /* #ifndef MATH_STANDALONE */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Int Conversion
+ *
+ * \note Python doesn't provide overflow checks for specific bit-widths.
+ *
+ * \{ */
+
+/* Compiler optimizes out redundant checks. */
+#ifdef __GNUC__
+# pragma warning(push)
+# pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
+/**
+ * Don't use `bool` return type, so -1 can be used as an error value.
+ */
+int PyC_Long_AsBool(PyObject *value)
+{
+ int test = _PyLong_AsInt(value);
+ if (UNLIKELY((uint)test > 1)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Python number not a bool (0/1)");
+ return -1;
+ }
+ return test;
+}
+
+int8_t PyC_Long_AsI8(PyObject *value)
+{
+ int test = _PyLong_AsInt(value);
+ if (UNLIKELY(test < INT8_MIN || test > INT8_MAX)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C int8");
+ return -1;
+ }
+ return (int8_t)test;
+}
+
+int16_t PyC_Long_AsI16(PyObject *value)
+{
+ int test = _PyLong_AsInt(value);
+ if (UNLIKELY(test < INT16_MIN || test > INT16_MAX)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C int16");
+ return -1;
+ }
+ return (int16_t)test;
+}
+
+/* Inlined in header:
+ * PyC_Long_AsI32
+ * PyC_Long_AsI64
+ */
+
+uint8_t PyC_Long_AsU8(PyObject *value)
+{
+ ulong test = PyLong_AsUnsignedLong(value);
+ if (UNLIKELY(test > UINT8_MAX)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C uint8");
+ return (uint8_t)-1;
+ }
+ return (uint8_t)test;
+}
+
+uint16_t PyC_Long_AsU16(PyObject *value)
+{
+ ulong test = PyLong_AsUnsignedLong(value);
+ if (UNLIKELY(test > UINT16_MAX)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C uint16");
+ return (uint16_t)-1;
+ }
+ return (uint16_t)test;
+}
+
+uint32_t PyC_Long_AsU32(PyObject *value)
+{
+ ulong test = PyLong_AsUnsignedLong(value);
+ if (UNLIKELY(test > UINT32_MAX)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C uint32");
+ return (uint32_t)-1;
+ }
+ return (uint32_t)test;
+}
+
+/* Inlined in header:
+ * PyC_Long_AsU64
+ */
+
+#ifdef __GNUC__
+# pragma warning(pop)
+#endif
+
+/** \} */
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 04cfc8801eb..327d4e60954 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -24,10 +24,12 @@
* \ingroup pygen
*/
-
#ifndef __PY_CAPI_UTILS_H__
#define __PY_CAPI_UTILS_H__
+#include "BLI_sys_types.h"
+#include "BLI_utildefines_variadic.h"
+
void PyC_ObSpit(const char *name, PyObject *var);
void PyC_LineSpit(void);
void PyC_StackSpit(void);
@@ -44,8 +46,21 @@ int PyC_AsArray_FAST(
int PyC_AsArray(
void *array, PyObject *value, const Py_ssize_t length,
const PyTypeObject *type, const bool is_double, const char *error_prefix);
-PyObject * PyC_FromArray(const void *array, int length, const PyTypeObject *type,
- const bool is_double, const char *error_prefix);
+
+PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len);
+PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len);
+PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len);
+PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len);
+
+#define PyC_Tuple_Pack_F32(...) \
+ PyC_Tuple_PackArray_F32(((const float []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+#define PyC_Tuple_Pack_I32(...) \
+ PyC_Tuple_PackArray_I32(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+#define PyC_Tuple_Pack_I32FromBool(...) \
+ PyC_Tuple_PackArray_I32FromBool(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+#define PyC_Tuple_Pack_Bool(...) \
+ PyC_Tuple_PackArray_Bool(((const bool []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value);
void PyC_List_Fill(PyObject *list, PyObject *value);
@@ -75,13 +90,36 @@ typedef struct PyC_FlagSet {
} PyC_FlagSet;
char *PyC_FlagSet_AsString(PyC_FlagSet *item);
-int PyC_FlagSet_ValueFromID_int(PyC_FlagSet *item, const char *identifier, int *value);
-int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int *value, const char *error_prefix);
+int PyC_FlagSet_ValueFromID_int(PyC_FlagSet *item, const char *identifier, int *r_value);
+int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int *r_value, const char *error_prefix);
int PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix);
PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag);
-bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filename);
+bool PyC_RunString_AsNumber(const char *expr, const char *filename, double *r_value);
+bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_value);
int PyC_ParseBool(PyObject *o, void *p);
+
+/* Integer parsing (with overflow checks), -1 on error. */
+int PyC_Long_AsBool(PyObject *value);
+int8_t PyC_Long_AsI8(PyObject *value);
+int16_t PyC_Long_AsI16(PyObject *value);
+#if 0 /* inline */
+int32_t PyC_Long_AsI32(PyObject *value);
+int64_t PyC_Long_AsI64(PyObject *value);
+#endif
+
+uint8_t PyC_Long_AsU8(PyObject *value);
+uint16_t PyC_Long_AsU16(PyObject *value);
+uint32_t PyC_Long_AsU32(PyObject *value);
+#if 0 /* inline */
+uint64_t PyC_Long_AsU64(PyObject *value);
+#endif
+
+/* inline so type signatures match as expected */
+Py_LOCAL_INLINE(int32_t) PyC_Long_AsI32(PyObject *value) { return (int32_t)_PyLong_AsInt(value); }
+Py_LOCAL_INLINE(int64_t) PyC_Long_AsI64(PyObject *value) { return (int64_t)PyLong_AsLongLong(value); }
+Py_LOCAL_INLINE(uint64_t) PyC_Long_AsU64(PyObject *value) { return (uint64_t)PyLong_AsUnsignedLongLong(value); }
+
#endif /* __PY_CAPI_UTILS_H__ */
diff --git a/source/blender/python/generic/python_utildefines.h b/source/blender/python/generic/python_utildefines.h
index f7d3e7a8b4a..2d2d19c05f5 100644
--- a/source/blender/python/generic/python_utildefines.h
+++ b/source/blender/python/generic/python_utildefines.h
@@ -36,16 +36,16 @@ extern "C" {
PyTupleObject *op = (PyTupleObject *)op_arg; \
PyObject **ob_items = op->ob_item; \
CHECK_TYPE_ANY(op_arg, PyObject *, PyTupleObject *); \
- BLI_assert(_VA_NARGS_COUNT(__VA_ARGS__) == PyTuple_GET_SIZE(op)); \
+ BLI_assert(VA_NARGS_COUNT(__VA_ARGS__) == PyTuple_GET_SIZE(op)); \
ARRAY_SET_ITEMS(ob_items, __VA_ARGS__); \
} (void)0
/* wrap Py_INCREF & return the result,
* use sparingly to avoid comma operator or temp var assignment */
-BLI_INLINE PyObject *Py_INCREF_RET(PyObject *op) { Py_INCREF(op); return op; }
+Py_LOCAL_INLINE(PyObject *)Py_INCREF_RET(PyObject *op) { Py_INCREF(op); return op; }
/* append & transfer ownership to the list, avoids inline Py_DECREF all over (which is quite a large macro) */
-BLI_INLINE int PyList_APPEND(PyObject *op, PyObject *v)
+Py_LOCAL_INLINE(int) PyList_APPEND(PyObject *op, PyObject *v)
{
int ret = PyList_Append(op, v);
Py_DecRef(v);
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 038c1e7eb10..dd84ce0ebe1 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -55,6 +55,7 @@ set(SRC
bpy_app_handlers.c
bpy_app_ocio.c
bpy_app_oiio.c
+ bpy_app_opensubdiv.c
bpy_app_openvdb.c
bpy_app_sdl.c
bpy_app_translations.c
@@ -89,6 +90,7 @@ set(SRC
bpy_app_handlers.h
bpy_app_ocio.h
bpy_app_oiio.h
+ bpy_app_opensubdiv.h
bpy_app_openvdb.h
bpy_app_sdl.h
bpy_app_translations.h
@@ -145,10 +147,6 @@ if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
endif()
-if(WITH_CODEC_QUICKTIME)
- add_definitions(-DWITH_QUICKTIME)
-endif()
-
if(WITH_CODEC_SNDFILE)
add_definitions(-DWITH_SNDFILE)
endif()
@@ -295,6 +293,13 @@ if(WITH_OPENIMAGEIO)
)
endif()
+if(WITH_OPENSUBDIV)
+ add_definitions(-DWITH_OPENSUBDIV)
+ list(APPEND INC
+ ../../../../intern/opensubdiv
+ )
+endif()
+
if(WITH_PLAYER)
add_definitions(-DWITH_PLAYER)
endif()
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 5bbfb4912e6..6e4a6148405 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -118,10 +118,11 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec
bool absolute = false;
bool packed = false;
bool local = false;
- static const char *kwlist[] = {"absolute", "packed", "local", NULL};
- if (!PyArg_ParseTupleAndKeywords(
- args, kw, "|O&O&O&:blend_paths", (char **)kwlist,
+ static const char *_keywords[] = {"absolute", "packed", "local", NULL};
+ static _PyArg_Parser _parser = {"|O&O&O&:blend_paths", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
PyC_ParseBool, &absolute,
PyC_ParseBool, &packed,
PyC_ParseBool, &local))
@@ -147,13 +148,18 @@ static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObj
const char *type;
const char *subdir = NULL;
int folder_id;
- static const char *kwlist[] = {"type", "subdir", NULL};
const char *path;
- if (!PyArg_ParseTupleAndKeywords(args, kw, "s|s:user_resource", (char **)kwlist, &type, &subdir))
+ static const char *_keywords[] = {"type", "subdir", NULL};
+ static _PyArg_Parser _parser = {"s|s:user_resource", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &type, &subdir))
+ {
return NULL;
-
+ }
+
/* stupid string compare */
if (STREQ(type, "DATAFILES")) folder_id = BLENDER_USER_DATAFILES;
else if (STREQ(type, "CONFIG")) folder_id = BLENDER_USER_CONFIG;
@@ -191,12 +197,17 @@ static PyObject *bpy_resource_path(PyObject *UNUSED(self), PyObject *args, PyObj
{
const char *type;
int major = BLENDER_VERSION / 100, minor = BLENDER_VERSION % 100;
- static const char *kwlist[] = {"type", "major", "minor", NULL};
int folder_id;
const char *path;
- if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ii:resource_path", (char **)kwlist, &type, &major, &minor))
+ static const char *_keywords[] = {"type", "major", "minor", NULL};
+ static _PyArg_Parser _parser = {"s|ii:resource_path", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &type, &major, &minor))
+ {
return NULL;
+ }
/* stupid string compare */
if (STREQ(type, "USER")) folder_id = BLENDER_RESOURCE_PATH_USER;
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index ed7cec2f2d5..f44401afd7d 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -37,6 +37,7 @@
#include "bpy_app_ffmpeg.h"
#include "bpy_app_ocio.h"
#include "bpy_app_oiio.h"
+#include "bpy_app_opensubdiv.h"
#include "bpy_app_openvdb.h"
#include "bpy_app_sdl.h"
#include "bpy_app_build_options.h"
@@ -88,6 +89,7 @@ static PyStructSequence_Field app_info_fields[] = {
{(char *)"version_cycle", (char *)"The release status of this build alpha/beta/rc/release"},
{(char *)"binary_path", (char *)"The location of blenders executable, useful for utilities that spawn new instances"},
{(char *)"background", (char *)"Boolean, True when blender is running without a user interface (started with -b)"},
+ {(char *)"factory_startup", (char *)"Boolean, True when blender is running with --factory-startup)"},
/* buildinfo */
{(char *)"build_date", (char *)"The date this blender instance was built"},
@@ -109,6 +111,7 @@ static PyStructSequence_Field app_info_fields[] = {
{(char *)"ffmpeg", (char *)"FFmpeg library information backend"},
{(char *)"ocio", (char *)"OpenColorIO library information backend"},
{(char *)"oiio", (char *)"OpenImageIO library information backend"},
+ {(char *)"opensubdiv", (char *)"OpenSubdiv library information backend"},
{(char *)"openvdb", (char *)"OpenVDB library information backend"},
{(char *)"sdl", (char *)"SDL library information backend"},
{(char *)"build_options", (char *)"A set containing most important enabled optional build features"},
@@ -117,9 +120,21 @@ static PyStructSequence_Field app_info_fields[] = {
{NULL},
};
+PyDoc_STRVAR(bpy_app_doc,
+"This module contains application values that remain unchanged during runtime.\n"
+"\n"
+"Submodules:\n"
+"\n"
+".. toctree::\n"
+" :maxdepth: 1\n"
+"\n"
+" bpy.app.handlers.rst\n"
+" bpy.app.translations.rst\n"
+);
+
static PyStructSequence_Desc app_info_desc = {
(char *)"bpy.app", /* name */
- (char *)"This module contains application values that remain unchanged during runtime.", /* doc */
+ bpy_app_doc, /* doc */
app_info_fields, /* fields */
ARRAY_SIZE(app_info_fields) - 1
};
@@ -142,8 +157,7 @@ static PyObject *make_app_info(void)
#define SetObjItem(obj) \
PyStructSequence_SET_ITEM(app_info, pos++, obj)
- SetObjItem(Py_BuildValue("(iii)",
- BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION));
+ SetObjItem(PyC_Tuple_Pack_I32(BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION));
SetObjItem(PyUnicode_FromFormat("%d.%02d (sub %d)",
BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION));
@@ -151,6 +165,7 @@ static PyObject *make_app_info(void)
SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE));
SetStrItem(BKE_appdir_program_path());
SetObjItem(PyBool_FromLong(G.background));
+ SetObjItem(PyBool_FromLong(G.factory_startup));
/* build info, use bytes since we can't assume _any_ encoding:
* see patch [#30154] for issue */
@@ -188,6 +203,7 @@ static PyObject *make_app_info(void)
SetObjItem(BPY_app_ffmpeg_struct());
SetObjItem(BPY_app_ocio_struct());
SetObjItem(BPY_app_oiio_struct());
+ SetObjItem(BPY_app_opensubdiv_struct());
SetObjItem(BPY_app_openvdb_struct());
SetObjItem(BPY_app_sdl_struct());
SetObjItem(BPY_app_build_options_struct());
@@ -275,7 +291,7 @@ static PyObject *bpy_app_debug_value_get(PyObject *UNUSED(self), void *UNUSED(cl
static int bpy_app_debug_value_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure))
{
- int param = PyLong_AsLong(value);
+ int param = PyC_Long_AsI32(value);
if (param == -1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "bpy.app.debug_value can only be set to a whole number");
diff --git a/source/blender/python/intern/bpy_app_alembic.c b/source/blender/python/intern/bpy_app_alembic.c
index 90e6a02b418..2a1a031a629 100644
--- a/source/blender/python/intern/bpy_app_alembic.c
+++ b/source/blender/python/intern/bpy_app_alembic.c
@@ -34,6 +34,8 @@
#include "bpy_app_alembic.h"
+#include "../generic/py_capi_utils.h"
+
#ifdef WITH_ALEMBIC
# include "ABC_alembic.h"
#endif
@@ -79,11 +81,11 @@ static PyObject *make_alembic_info(void)
const int patch = curversion - ((curversion / 100 ) * 100);
SetObjItem(PyBool_FromLong(1));
- SetObjItem(Py_BuildValue("(iii)", major, minor, patch));
+ SetObjItem(PyC_Tuple_Pack_I32(major, minor, patch));
SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", major, minor, patch));
#else
SetObjItem(PyBool_FromLong(0));
- SetObjItem(Py_BuildValue("(iii)", 0, 0, 0));
+ SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0));
SetStrItem("Unknown");
#endif
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index a6b98567a9a..501e09dd6ad 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -37,7 +37,6 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"bullet", NULL},
{(char *)"codec_avi", NULL},
{(char *)"codec_ffmpeg", NULL},
- {(char *)"codec_quicktime", NULL},
{(char *)"codec_sndfile", NULL},
{(char *)"compositor", NULL},
{(char *)"cycles", NULL},
@@ -112,12 +111,6 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
-#ifdef WITH_QUICKTIME
- SetObjIncref(Py_True);
-#else
- SetObjIncref(Py_False);
-#endif
-
#ifdef WITH_SNDFILE
SetObjIncref(Py_True);
#else
diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c
index fd516e4547f..9f8355db72b 100644
--- a/source/blender/python/intern/bpy_app_ffmpeg.c
+++ b/source/blender/python/intern/bpy_app_ffmpeg.c
@@ -29,6 +29,8 @@
#include "bpy_app_ffmpeg.h"
+#include "../generic/py_capi_utils.h"
+
#ifdef WITH_FFMPEG
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
@@ -91,8 +93,7 @@ static PyObject *make_ffmpeg_info(void)
#ifdef WITH_FFMPEG
# define FFMPEG_LIB_VERSION(lib) { \
curversion = lib ## _version(); \
- SetObjItem(Py_BuildValue("(iii)", \
- curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \
+ SetObjItem(PyC_Tuple_Pack_I32(curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \
SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", \
curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \
} (void)0
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index 1cc2d6f1307..90aa22de5bf 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -59,8 +59,12 @@ static PyStructSequence_Field app_cb_info_fields[] = {
{(char *)"load_post", (char *)"on loading a new blend file (after)"},
{(char *)"save_pre", (char *)"on saving a blend file (before)"},
{(char *)"save_post", (char *)"on saving a blend file (after)"},
- {(char *)"scene_update_pre", (char *)"on updating the scenes data (before)"},
- {(char *)"scene_update_post", (char *)"on updating the scenes data (after)"},
+ {(char *)"scene_update_pre", (char *)"on every scene data update. Does not imply that anything changed in the "
+ "scene, just that the dependency graph is about to be reevaluated, and the "
+ "scene is about to be updated by Blender's animation system."},
+ {(char *)"scene_update_post", (char *)"on every scene data update. Does not imply that anything changed in the "
+ "scene, just that the dependency graph was reevaluated, and the scene was "
+ "possibly updated by Blender's animation system."},
{(char *)"game_pre", (char *)"on starting the game engine"},
{(char *)"game_post", (char *)"on ending the game engine"},
{(char *)"version_update", (char *)"on ending the versioning code"},
@@ -126,7 +130,7 @@ static PyObject *bpy_app_handlers_persistent_new(PyTypeObject *UNUSED(type), PyO
/* dummy type because decorators can't be PyCFunctions */
static PyTypeObject BPyPersistent_Type = {
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
PyVarObject_HEAD_INIT(NULL, 0)
#else
PyVarObject_HEAD_INIT(&PyType_Type, 0)
@@ -206,7 +210,7 @@ PyObject *BPY_app_handlers_struct(void)
{
PyObject *ret;
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
BPyPersistent_Type.ob_base.ob_base.ob_type = &PyType_Type;
#endif
diff --git a/source/blender/python/intern/bpy_app_ocio.c b/source/blender/python/intern/bpy_app_ocio.c
index 02e4044219a..9997e6b87f1 100644
--- a/source/blender/python/intern/bpy_app_ocio.c
+++ b/source/blender/python/intern/bpy_app_ocio.c
@@ -29,6 +29,8 @@
#include "bpy_app_ocio.h"
+#include "../generic/py_capi_utils.h"
+
#ifdef WITH_OCIO
# include "ocio_capi.h"
#endif
@@ -74,13 +76,12 @@ static PyObject *make_ocio_info(void)
#ifdef WITH_OCIO
curversion = OCIO_getVersionHex();
SetObjItem(PyBool_FromLong(1));
- SetObjItem(Py_BuildValue("(iii)",
- curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256));
+ SetObjItem(PyC_Tuple_Pack_I32(curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256));
SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d",
curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256));
#else
SetObjItem(PyBool_FromLong(0));
- SetObjItem(Py_BuildValue("(iii)", 0, 0, 0));
+ SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0));
SetStrItem("Unknown");
#endif
diff --git a/source/blender/python/intern/bpy_app_oiio.c b/source/blender/python/intern/bpy_app_oiio.c
index 60daf3ddd8b..e14b48ff7cf 100644
--- a/source/blender/python/intern/bpy_app_oiio.c
+++ b/source/blender/python/intern/bpy_app_oiio.c
@@ -29,6 +29,8 @@
#include "bpy_app_oiio.h"
+#include "../generic/py_capi_utils.h"
+
#ifdef WITH_OPENIMAGEIO
# include "openimageio_api.h"
#endif
@@ -74,13 +76,12 @@ static PyObject *make_oiio_info(void)
#ifdef WITH_OPENIMAGEIO
curversion = OIIO_getVersionHex();
SetObjItem(PyBool_FromLong(1));
- SetObjItem(Py_BuildValue("(iii)",
- curversion / 10000, (curversion / 100) % 100, curversion % 100));
+ SetObjItem(PyC_Tuple_Pack_I32(curversion / 10000, (curversion / 100) % 100, curversion % 100));
SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d",
curversion / 10000, (curversion / 100) % 100, curversion % 100));
#else
SetObjItem(PyBool_FromLong(0));
- SetObjItem(Py_BuildValue("(iii)", 0, 0, 0));
+ SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0));
SetStrItem("Unknown");
#endif
diff --git a/source/blender/python/intern/bpy_app_opensubdiv.c b/source/blender/python/intern/bpy_app_opensubdiv.c
new file mode 100644
index 00000000000..096374794c9
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_opensubdiv.c
@@ -0,0 +1,110 @@
+/*
+ * ***** 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.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_opensubdiv.c
+ * \ingroup pythonintern
+ */
+
+#include <Python.h>
+#include "BLI_utildefines.h"
+
+#include "bpy_app_opensubdiv.h"
+
+#include "../generic/py_capi_utils.h"
+
+#ifdef WITH_OPENSUBDIV
+# include "opensubdiv_capi.h"
+#endif
+
+static PyTypeObject BlenderAppOpenSubdivType;
+
+static PyStructSequence_Field app_opensubdiv_info_fields[] = {
+ {(char *)"supported", (char *)("Boolean, True when Blender is built with OpenSubdiv support")},
+ {(char *)("version"), (char *)("The OpenSubdiv version as a tuple of 3 numbers")},
+ {(char *)("version_string"), (char *)("The OpenSubdiv version formatted as a string")},
+ {NULL}
+};
+
+static PyStructSequence_Desc app_opensubdiv_info_desc = {
+ (char *)"bpy.app.opensubdiv", /* name */
+ (char *)"This module contains information about OpenSubdiv blender is linked against", /* doc */
+ app_opensubdiv_info_fields, /* fields */
+ ARRAY_SIZE(app_opensubdiv_info_fields) - 1
+};
+
+static PyObject *make_opensubdiv_info(void)
+{
+ PyObject *opensubdiv_info;
+ int pos = 0;
+
+ opensubdiv_info = PyStructSequence_New(&BlenderAppOpenSubdivType);
+ if (opensubdiv_info == NULL) {
+ return NULL;
+ }
+
+#ifndef WITH_OPENSUBDIV
+#define SetStrItem(str) \
+ PyStructSequence_SET_ITEM(opensubdiv_info, pos++, PyUnicode_FromString(str))
+#endif
+
+#define SetObjItem(obj) \
+ PyStructSequence_SET_ITEM(opensubdiv_info, pos++, obj)
+
+#ifdef WITH_OPENSUBDIV
+ int curversion = openSubdiv_getVersionHex();
+ SetObjItem(PyBool_FromLong(1));
+ SetObjItem(PyC_Tuple_Pack_I32(curversion / 10000, (curversion / 100) % 100, curversion % 100));
+ SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d",
+ curversion / 10000, (curversion / 100) % 100, curversion % 100));
+#else
+ SetObjItem(PyBool_FromLong(0));
+ SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0));
+ SetStrItem("Unknown");
+#endif
+
+ if (PyErr_Occurred()) {
+ Py_CLEAR(opensubdiv_info);
+ return NULL;
+ }
+
+#undef SetStrItem
+#undef SetObjItem
+
+ return opensubdiv_info;
+}
+
+PyObject *BPY_app_opensubdiv_struct(void)
+{
+ PyObject *ret;
+
+ PyStructSequence_InitType(&BlenderAppOpenSubdivType, &app_opensubdiv_info_desc);
+
+ ret = make_opensubdiv_info();
+
+ /* prevent user from creating new instances */
+ BlenderAppOpenSubdivType.tp_init = NULL;
+ BlenderAppOpenSubdivType.tp_new = NULL;
+ /* without this we can't do set(sys.modules) [#29635] */
+ BlenderAppOpenSubdivType.tp_hash = (hashfunc)_Py_HashPointer;
+
+ return ret;
+}
diff --git a/source/blender/depsgraph/util/deg_util_hash.h b/source/blender/python/intern/bpy_app_opensubdiv.h
index e490be1a7a1..b1da218b168 100644
--- a/source/blender/depsgraph/util/deg_util_hash.h
+++ b/source/blender/python/intern/bpy_app_opensubdiv.h
@@ -15,27 +15,18 @@
* 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) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Brecht van Lommel
- * Contributor(s): Lukas Toenne
+ * Contributor(s): Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/deg_util_hash.h
- * \ingroup depsgraph
+/** \file blender/python/intern/bpy_app_opensubdiv.h
+ * \ingroup pythonintern
*/
-#pragma once
-
-#include "BLI_utildefines.h"
+#ifndef __BPY_APP_OPENSUBDIV_H__
+#define __BPY_APP_OPENSUBDIV_H__
-#include "BLI_ghash.h"
+PyObject *BPY_app_opensubdiv_struct(void);
-/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
-BLI_INLINE size_t hash_combine(size_t hash_a, size_t hash_b)
-{
- return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
-}
+#endif /* __BPY_APP_OPENSUBDIV_H__ */
diff --git a/source/blender/python/intern/bpy_app_openvdb.c b/source/blender/python/intern/bpy_app_openvdb.c
index 8a24aaf0555..0b385206d7b 100644
--- a/source/blender/python/intern/bpy_app_openvdb.c
+++ b/source/blender/python/intern/bpy_app_openvdb.c
@@ -34,6 +34,8 @@
#include "bpy_app_openvdb.h"
+#include "../generic/py_capi_utils.h"
+
#ifdef WITH_OPENVDB
# include "openvdb_capi.h"
#endif
@@ -79,13 +81,12 @@ static PyObject *make_openvdb_info(void)
#ifdef WITH_OPENVDB
curversion = OpenVDB_getVersionHex();
SetObjItem(PyBool_FromLong(1));
- SetObjItem(Py_BuildValue("(iii)",
- curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256));
+ SetObjItem(PyC_Tuple_Pack_I32(curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256));
SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d",
curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256));
#else
SetObjItem(PyBool_FromLong(0));
- SetObjItem(Py_BuildValue("(iii)", 0, 0, 0));
+ SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0));
SetStrItem("Unknown");
#endif
diff --git a/source/blender/python/intern/bpy_app_sdl.c b/source/blender/python/intern/bpy_app_sdl.c
index 2f4d8e6c325..816ad2833cc 100644
--- a/source/blender/python/intern/bpy_app_sdl.c
+++ b/source/blender/python/intern/bpy_app_sdl.c
@@ -29,6 +29,8 @@
#include "bpy_app_sdl.h"
+#include "../generic/py_capi_utils.h"
+
#ifdef WITH_SDL
/* SDL force defines __SSE__ and __SSE2__ flags, which generates warnings
* because we pass those defines via command line as well. For until there's
@@ -56,7 +58,7 @@ static PyStructSequence_Field app_sdl_info_fields[] = {
{(char *)"available", (char *)("Boolean, True when SDL is available. This is False when "
"either *supported* is False, or *dynload* is True and "
"Blender cannot find the correct library.")},
- {NULL}
+ {NULL}
};
static PyStructSequence_Desc app_sdl_info_desc = {
@@ -103,7 +105,7 @@ static PyObject *make_sdl_info(void)
# endif
# endif
- SetObjItem(Py_BuildValue("(iii)", version.major, version.minor, version.patch));
+ SetObjItem(PyC_Tuple_Pack_I32(version.major, version.minor, version.patch));
if (sdl_available) {
SetObjItem(PyUnicode_FromFormat("%d.%d.%d", version.major, version.minor, version.patch));
}
@@ -114,7 +116,7 @@ static PyObject *make_sdl_info(void)
#else // WITH_SDL=OFF
SetObjItem(PyBool_FromLong(0));
- SetObjItem(Py_BuildValue("(iii)", 0, 0, 0));
+ SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0));
SetStrItem("Unknown");
SetObjItem(PyBool_FromLong(0));
#endif
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 311f621e13b..20cfd364a0c 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -480,11 +480,20 @@ static bool python_script_exec(
* object, but as written in the Python/C API Ref Manual, chapter 2,
* 'FILE structs for different C libraries can be different and
* incompatible'.
- * So now we load the script file data to a buffer */
+ * So now we load the script file data to a buffer.
+ *
+ * Note on use of 'globals()', it's important not copy the dictionary because
+ * tools may inspect 'sys.modules["__main__"]' for variables defined in the code
+ * where using a copy of 'globals()' causes code execution
+ * to leave the main namespace untouched. see: T51444
+ *
+ * This leaves us with the problem of variables being included,
+ * currently this is worked around using 'dict.__del__' it's ugly but works.
+ */
{
const char *pystring =
- "ns = globals().copy()\n"
- "with open(__file__, 'rb') as f: exec(compile(f.read(), __file__, 'exec'), ns)";
+ "with open(__file__, 'rb') as f:"
+ "exec(compile(f.read(), __file__, 'exec'), globals().__delitem__('f') or globals())";
fclose(fp);
@@ -572,21 +581,58 @@ void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
/**
* \return success
*/
-bool BPY_execute_string_as_number(bContext *C, const char *expr, double *value, const bool verbose)
+bool BPY_execute_string_as_number(bContext *C, const char *expr, const bool verbose, double *r_value)
{
PyGILState_STATE gilstate;
bool ok = true;
- if (!value || !expr) return -1;
+ if (!r_value || !expr) {
+ return -1;
+ }
+
+ if (expr[0] == '\0') {
+ *r_value = 0.0;
+ return ok;
+ }
+
+ bpy_context_set(C, &gilstate);
+
+ ok = PyC_RunString_AsNumber(expr, "<blender button>", r_value);
+
+ if (ok == false) {
+ if (verbose) {
+ BPy_errors_to_report_ex(CTX_wm_reports(C), false, false);
+ }
+ else {
+ PyErr_Clear();
+ }
+ }
+
+ bpy_context_clear(C, &gilstate);
+
+ return ok;
+}
+
+/**
+ * \return success
+ */
+bool BPY_execute_string_as_string(bContext *C, const char *expr, const bool verbose, char **r_value)
+{
+ PyGILState_STATE gilstate;
+ bool ok = true;
+
+ if (!r_value || !expr) {
+ return -1;
+ }
if (expr[0] == '\0') {
- *value = 0.0;
+ *r_value = NULL;
return ok;
}
bpy_context_set(C, &gilstate);
- ok = PyC_RunString_AsNumber(expr, value, "<blender button>");
+ ok = PyC_RunString_AsString(expr, "<blender button>", r_value);
if (ok == false) {
if (verbose) {
@@ -602,6 +648,7 @@ bool BPY_execute_string_as_number(bContext *C, const char *expr, double *value,
return ok;
}
+
bool BPY_execute_string_ex(bContext *C, const char *expr, bool use_eval)
{
PyGILState_STATE gilstate;
@@ -822,6 +869,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy)
BLI_strncpy(filename_abs, filename_rel, sizeof(filename_abs));
BLI_path_cwd(filename_abs, sizeof(filename_abs));
+ Py_DECREF(filename_obj);
argv[0] = filename_abs;
argv[1] = NULL;
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 15f3c665fcf..39fce293bd0 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -73,7 +73,7 @@ typedef struct {
} BPy_Library;
static PyObject *bpy_lib_load(PyObject *self, PyObject *args, PyObject *kwds);
-static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *args);
+static PyObject *bpy_lib_enter(BPy_Library *self);
static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *args);
static PyObject *bpy_lib_dir(BPy_Library *self);
@@ -183,17 +183,17 @@ PyDoc_STRVAR(bpy_lib_load_doc,
" :arg relative: When True the path is stored relative to the open blend file.\n"
" :type relative: bool\n"
);
-static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- static const char *kwlist[] = {"filepath", "link", "relative", NULL};
Main *bmain = CTX_data_main(BPy_GetContext());
BPy_Library *ret;
const char *filename = NULL;
bool is_rel = false, is_link = false;
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds,
- "s|O&O&:load", (char **)kwlist,
+ static const char *_keywords[] = {"filepath", "link", "relative", NULL};
+ static _PyArg_Parser _parser = {"s|O&O&:load", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
&filename,
PyC_ParseBool, &is_link,
PyC_ParseBool, &is_rel))
@@ -237,7 +237,7 @@ static PyObject *_bpy_names(BPy_Library *self, int blocktype)
return list;
}
-static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args))
+static PyObject *bpy_lib_enter(BPy_Library *self)
{
PyObject *ret;
BPy_Library *self_from;
diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c
index bf91253141a..c054183034a 100644
--- a/source/blender/python/intern/bpy_library_write.c
+++ b/source/blender/python/intern/bpy_library_write.c
@@ -69,24 +69,23 @@ PyDoc_STRVAR(bpy_lib_write_doc,
" :arg compress: When True, write a compressed blend file.\n"
" :type compress: bool\n"
);
-static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- static const char *kwlist[] = {
- "filepath", "datablocks",
- /* optional */
- "relative_remap", "fake_user", "compress",
- NULL,
- };
-
/* args */
const char *filepath;
char filepath_abs[FILE_MAX];
PyObject *datablocks = NULL;
bool use_relative_remap = false, use_fake_user = false, use_compress = false;
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds,
- "sO!|$O&O&O&:write", (char **)kwlist,
+ static const char *_keywords[] = {
+ "filepath", "datablocks",
+ /* optional */
+ "relative_remap", "fake_user", "compress",
+ NULL,
+ };
+ static _PyArg_Parser _parser = {"sO!|$O&O&O&:write", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
&filepath,
&PySet_Type, &datablocks,
PyC_ParseBool, &use_relative_remap,
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index bd3e5736c6c..c1fcb0792af 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -450,7 +450,7 @@ static PyObject *pyop_getinstance(PyObject *UNUSED(self), PyObject *value)
op = PyMem_MALLOC(sizeof(wmOperator));
memset(op, 0, sizeof(wmOperator));
#endif
- BLI_strncpy(op->idname, op->idname, sizeof(op->idname)); /* in case its needed */
+ BLI_strncpy(op->idname, ot->idname, sizeof(op->idname)); /* in case its needed */
op->type = ot;
RNA_pointer_create(NULL, &RNA_Operator, op, &ptr);
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index 11e27ca3e3c..9d57adca946 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -48,10 +48,12 @@ static void operator_properties_init(wmOperatorType *ot)
PyTypeObject *py_class = ot->ext.data;
RNA_struct_blender_type_set(ot->ext.srna, ot);
- /* only call this so pyrna_deferred_register_class gives a useful error
- * WM_operatortype_append_ptr will call RNA_def_struct_identifier
- * later */
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ /* Only call this so pyrna_deferred_register_class gives a useful error
+ * WM_operatortype_append_ptr will call RNA_def_struct_identifier later.
+ *
+ * Note the 'no_struct_map' function is used since the actual struct name is already used by the operator.
+ */
+ RNA_def_struct_identifier_no_struct_map(ot->srna, ot->idname);
if (pyrna_deferred_register_class(ot->srna, py_class) != 0) {
PyErr_Print(); /* failed to register operator props */
@@ -118,7 +120,7 @@ static void operator_properties_init(wmOperatorType *ot)
}
-void operator_wrapper(wmOperatorType *ot, void *userdata)
+void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
{
/* take care not to overwrite anything set in
* WM_operatortype_append_ptr before opfunc() is called */
@@ -134,7 +136,7 @@ void operator_wrapper(wmOperatorType *ot, void *userdata)
operator_properties_init(ot);
}
-void macro_wrapper(wmOperatorType *ot, void *userdata)
+void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata)
{
wmOperatorType *data = (wmOperatorType *)userdata;
diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h
index 05a566a1485..0828c58e2bd 100644
--- a/source/blender/python/intern/bpy_operator_wrap.h
+++ b/source/blender/python/intern/bpy_operator_wrap.h
@@ -33,7 +33,7 @@ struct wmOperatorType;
PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args);
/* exposed to rna/wm api */
-void operator_wrapper(struct wmOperatorType *ot, void *userdata);
-void macro_wrapper(struct wmOperatorType *ot, void *userdata);
+void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata);
+void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata);
#endif
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index e61018865ab..a46fda7ea63 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -50,11 +50,13 @@
#include "../generic/py_capi_utils.h"
/* initial definition of callback slots we'll probably have more than 1 */
-#define BPY_DATA_CB_SLOT_SIZE 3
-
-#define BPY_DATA_CB_SLOT_UPDATE 0
-#define BPY_DATA_CB_SLOT_GET 1
-#define BPY_DATA_CB_SLOT_SET 2
+enum {
+ BPY_DATA_CB_SLOT_UPDATE = 0,
+ BPY_DATA_CB_SLOT_GET = 1,
+ BPY_DATA_CB_SLOT_SET = 2,
+ BPY_DATA_CB_SLOT_POLL = 3,
+ BPY_DATA_CB_SLOT_SIZE = 4,
+};
extern BPy_StructRNA *bpy_context_module;
@@ -71,6 +73,9 @@ static EnumPropertyItem property_flag_items[] = {
" :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', 'PROPORTIONAL'," \
"'TEXTEDIT_UPDATE'].\n" \
" :type options: set\n" \
+" :arg poll: function to be called to determine whether an item is valid for this property.\n" \
+" The function must take 2 values (self,object) and return Bool.\n" \
+" :type poll: function\n" \
static EnumPropertyItem property_flag_enum_items[] = {
{PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
@@ -230,7 +235,7 @@ static PyObject *bpy_prop_deferred_return(PyObject *func, PyObject *kw)
static void bpy_prop_update_cb(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop)
{
PyGILState_STATE gilstate;
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -279,7 +284,7 @@ static void bpy_prop_update_cb(struct bContext *C, struct PointerRNA *ptr, struc
static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -315,7 +320,7 @@ static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
value = false;
}
else {
- value = PyLong_AsLong(ret);
+ value = PyC_Long_AsI32(ret);
if (value == -1 && PyErr_Occurred()) {
printf_func_error(py_func);
@@ -337,7 +342,7 @@ static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -389,9 +394,54 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *
}
}
+static int bpy_prop_poll_cb(struct PointerRNA *self, PointerRNA candidate, struct PropertyRNA *prop)
+{
+ PyObject *py_self;
+ PyObject *py_candidate;
+ PyObject *py_func;
+ PyObject **py_data = RNA_property_py_data_get(prop);
+ PyObject *args;
+ PyObject *ret;
+ bool result;
+ const int is_write_ok = pyrna_write_check();
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ BLI_assert(self != NULL);
+
+ py_self = pyrna_struct_as_instance(self);
+ py_candidate = pyrna_struct_as_instance(&candidate);
+ py_func = py_data[BPY_DATA_CB_SLOT_POLL];
+
+ if (!is_write_ok)
+ pyrna_write_set(true);
+
+ args = PyTuple_New(2);
+ PyTuple_SET_ITEM(args, 0, py_self);
+ PyTuple_SET_ITEM(args, 1, py_candidate);
+
+ ret = PyObject_CallObject(py_func, args);
+
+ Py_DECREF(args);
+
+ if (ret == NULL) {
+ printf_func_error(py_func);
+ result = false;
+ }
+ else {
+ result = PyObject_IsTrue(ret);
+ Py_DECREF(ret);
+ }
+
+ PyGILState_Release(gilstate);
+ if (!is_write_ok)
+ pyrna_write_set(false);
+
+ return result;
+}
+
static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -452,7 +502,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct Propert
static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -480,12 +530,8 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct Propert
self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEM(args, 0, self);
- py_values = PyC_FromArray(values, len, &PyBool_Type, false, "BoolVectorProperty set");
- if (!py_values) {
- printf_func_error(py_func);
- }
- else
- PyTuple_SET_ITEM(args, 1, py_values);
+ py_values = PyC_Tuple_PackArray_I32FromBool(values, len);
+ PyTuple_SET_ITEM(args, 1, py_values);
ret = PyObject_CallObject(py_func, args);
@@ -513,7 +559,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct Propert
static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -549,7 +595,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
value = 0.0f;
}
else {
- value = PyLong_AsLong(ret);
+ value = PyC_Long_AsI32(ret);
if (value == -1 && PyErr_Occurred()) {
printf_func_error(py_func);
@@ -571,7 +617,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -625,7 +671,7 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -686,7 +732,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA
static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -714,12 +760,8 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA
self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEM(args, 0, self);
- py_values = PyC_FromArray(values, len, &PyLong_Type, false, "IntVectorProperty set");
- if (!py_values) {
- printf_func_error(py_func);
- }
- else
- PyTuple_SET_ITEM(args, 1, py_values);
+ py_values = PyC_Tuple_PackArray_I32(values, len);
+ PyTuple_SET_ITEM(args, 1, py_values);
ret = PyObject_CallObject(py_func, args);
@@ -747,7 +789,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA
static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -805,7 +847,7 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, float value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -859,7 +901,7 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr
static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, float *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -920,7 +962,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr, struct PropertyR
static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const float *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -948,12 +990,8 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyR
self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEM(args, 0, self);
- py_values = PyC_FromArray(values, len, &PyFloat_Type, false, "FloatVectorProperty set");
- if (!py_values) {
- printf_func_error(py_func);
- }
- else
- PyTuple_SET_ITEM(args, 1, py_values);
+ py_values = PyC_Tuple_PackArray_F32(values, len);
+ PyTuple_SET_ITEM(args, 1, py_values);
ret = PyObject_CallObject(py_func, args);
@@ -981,7 +1019,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyR
static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, char *value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1040,7 +1078,7 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1102,7 +1140,7 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA
static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const char *value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1163,7 +1201,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1199,7 +1237,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
value = RNA_property_enum_get_default(ptr, prop);
}
else {
- value = PyLong_AsLong(ret);
+ value = PyC_Long_AsI32(ret);
if (value == -1 && PyErr_Occurred()) {
printf_func_error(py_func);
@@ -1221,7 +1259,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1598,6 +1636,16 @@ static void bpy_prop_callback_assign_update(struct PropertyRNA *prop, PyObject *
}
}
+static void bpy_prop_callback_assign_pointer(struct PropertyRNA *prop, PyObject *poll_cb)
+{
+ if (poll_cb && poll_cb != Py_None) {
+ PyObject **py_data = bpy_prop_py_data_get(prop);
+
+ RNA_def_property_poll_runtime(prop, (void *) bpy_prop_poll_cb);
+ py_data[BPY_DATA_CB_SLOT_POLL] = poll_cb;
+ }
+}
+
static void bpy_prop_callback_assign_boolean(struct PropertyRNA *prop, PyObject *get_cb, PyObject *set_cb)
{
BooleanPropertyGetFunc rna_get_cb = NULL;
@@ -1904,7 +1952,7 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop, PyObject *ge
" :type set: function\n" \
#define BPY_PROPDEF_TYPE_DOC \
-" :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" \
+" :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \
" :type type: class\n" \
#if 0
@@ -1947,8 +1995,6 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
BPY_PROPDEF_HEAD(BoolProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "name", "description", "default",
- "options", "subtype", "update", "get", "set", NULL};
const char *id = NULL, *name = NULL, *description = "";
int id_len;
bool def = false;
@@ -1961,12 +2007,17 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *get_cb = NULL;
PyObject *set_cb = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssO&O!sOOO:BoolProperty",
- (char **)kwlist, &id, &id_len,
- &name, &description, PyC_ParseBool, &def,
- &PySet_Type, &pyopts, &pysubtype,
- &update_cb, &get_cb, &set_cb))
+ static const char *_keywords[] = {
+ "attr", "name", "description", "default",
+ "options", "subtype", "update", "get", "set", NULL,
+ };
+ static _PyArg_Parser _parser = {"s#|ssO&O!sOOO:BoolProperty", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &id, &id_len,
+ &name, &description, PyC_ParseBool, &def,
+ &PySet_Type, &pyopts, &pysubtype,
+ &update_cb, &get_cb, &set_cb))
{
return NULL;
}
@@ -2029,8 +2080,6 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
BPY_PROPDEF_HEAD(BoolVectorProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "name", "description", "default",
- "options", "subtype", "size", "update", "get", "set", NULL};
const char *id = NULL, *name = NULL, *description = "";
int id_len;
int def[PYRNA_STACK_ARRAY] = {0};
@@ -2045,12 +2094,17 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
PyObject *get_cb = NULL;
PyObject *set_cb = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssOO!siOOO:BoolVectorProperty",
- (char **)kwlist, &id, &id_len,
- &name, &description, &pydef,
- &PySet_Type, &pyopts, &pysubtype, &size,
- &update_cb, &get_cb, &set_cb))
+ static const char *_keywords[] = {
+ "attr", "name", "description", "default",
+ "options", "subtype", "size", "update", "get", "set", NULL,
+ };
+ static _PyArg_Parser _parser = {"s#|ssOO!siOOO:BoolVectorProperty", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &id, &id_len,
+ &name, &description, &pydef,
+ &PySet_Type, &pyopts, &pysubtype, &size,
+ &update_cb, &get_cb, &set_cb))
{
return NULL;
}
@@ -2133,9 +2187,6 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
BPY_PROPDEF_HEAD(IntProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "name", "description", "default",
- "min", "max", "soft_min", "soft_max",
- "step", "options", "subtype", "update", "get", "set", NULL};
const char *id = NULL, *name = NULL, *description = "";
int id_len;
int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1, def = 0;
@@ -2148,13 +2199,19 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *get_cb = NULL;
PyObject *set_cb = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssiiiiiiO!sOOO:IntProperty",
- (char **)kwlist, &id, &id_len,
- &name, &description, &def,
- &min, &max, &soft_min, &soft_max,
- &step, &PySet_Type, &pyopts, &pysubtype,
- &update_cb, &get_cb, &set_cb))
+ static const char *_keywords[] = {
+ "attr", "name", "description", "default",
+ "min", "max", "soft_min", "soft_max",
+ "step", "options", "subtype", "update", "get", "set", NULL,
+ };
+ static _PyArg_Parser _parser = {"s#|ssiiiiiiO!sOOO:IntProperty", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &id, &id_len,
+ &name, &description, &def,
+ &min, &max, &soft_min, &soft_max,
+ &step, &PySet_Type, &pyopts, &pysubtype,
+ &update_cb, &get_cb, &set_cb))
{
return NULL;
}
@@ -2230,9 +2287,6 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
BPY_PROPDEF_HEAD(IntVectorProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "name", "description", "default",
- "min", "max", "soft_min", "soft_max",
- "step", "options", "subtype", "size", "update", "get", "set", NULL};
const char *id = NULL, *name = NULL, *description = "";
int id_len;
int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1;
@@ -2248,14 +2302,20 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
PyObject *get_cb = NULL;
PyObject *set_cb = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssOiiiiiO!siOOO:IntVectorProperty",
- (char **)kwlist, &id, &id_len,
- &name, &description, &pydef,
- &min, &max, &soft_min, &soft_max,
- &step, &PySet_Type, &pyopts,
- &pysubtype, &size,
- &update_cb, &get_cb, &set_cb))
+ static const char *_keywords[] = {
+ "attr", "name", "description", "default",
+ "min", "max", "soft_min", "soft_max",
+ "step", "options", "subtype", "size", "update", "get", "set", NULL,
+ };
+ static _PyArg_Parser _parser = {"s#|ssOiiiiiO!siOOO:IntVectorProperty", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &id, &id_len,
+ &name, &description, &pydef,
+ &min, &max, &soft_min, &soft_max,
+ &step, &PySet_Type, &pyopts,
+ &pysubtype, &size,
+ &update_cb, &get_cb, &set_cb))
{
return NULL;
}
@@ -2343,10 +2403,6 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
BPY_PROPDEF_HEAD(FloatProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "name", "description", "default",
- "min", "max", "soft_min", "soft_max",
- "step", "precision", "options", "subtype",
- "unit", "update", "get", "set", NULL};
const char *id = NULL, *name = NULL, *description = "";
int id_len;
float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3, def = 0.0f;
@@ -2362,14 +2418,21 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *get_cb = NULL;
PyObject *set_cb = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssffffffiO!ssOOO:FloatProperty",
- (char **)kwlist, &id, &id_len,
- &name, &description, &def,
- &min, &max, &soft_min, &soft_max,
- &step, &precision, &PySet_Type,
- &pyopts, &pysubtype, &pyunit,
- &update_cb, &get_cb, &set_cb))
+ static const char *_keywords[] = {
+ "attr", "name", "description", "default",
+ "min", "max", "soft_min", "soft_max",
+ "step", "precision", "options", "subtype",
+ "unit", "update", "get", "set", NULL,
+ };
+ static _PyArg_Parser _parser = {"s#|ssffffffiO!ssOOO:FloatProperty", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &id, &id_len,
+ &name, &description, &def,
+ &min, &max, &soft_min, &soft_max,
+ &step, &precision, &PySet_Type,
+ &pyopts, &pysubtype, &pyunit,
+ &update_cb, &get_cb, &set_cb))
{
return NULL;
}
@@ -2454,10 +2517,6 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
BPY_PROPDEF_HEAD(FloatVectorProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "name", "description", "default",
- "min", "max", "soft_min", "soft_max",
- "step", "precision", "options", "subtype",
- "unit", "size", "update", "get", "set", NULL};
const char *id = NULL, *name = NULL, *description = "";
int id_len;
float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3;
@@ -2475,14 +2534,21 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
PyObject *get_cb = NULL;
PyObject *set_cb = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssOfffffiO!ssiOOO:FloatVectorProperty",
- (char **)kwlist, &id, &id_len,
- &name, &description, &pydef,
- &min, &max, &soft_min, &soft_max,
- &step, &precision, &PySet_Type,
- &pyopts, &pysubtype, &pyunit, &size,
- &update_cb, &get_cb, &set_cb))
+ static const char *_keywords[] = {
+ "attr", "name", "description", "default",
+ "min", "max", "soft_min", "soft_max",
+ "step", "precision", "options", "subtype",
+ "unit", "size", "update", "get", "set", NULL,
+ };
+ static _PyArg_Parser _parser = {"s#|ssOfffffiO!ssiOOO:FloatVectorProperty", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &id, &id_len,
+ &name, &description, &pydef,
+ &min, &max, &soft_min, &soft_max,
+ &step, &precision, &PySet_Type,
+ &pyopts, &pysubtype, &pyunit, &size,
+ &update_cb, &get_cb, &set_cb))
{
return NULL;
}
@@ -2563,8 +2629,6 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
BPY_PROPDEF_HEAD(StringProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "name", "description", "default",
- "maxlen", "options", "subtype", "update", "get", "set", NULL};
const char *id = NULL, *name = NULL, *description = "", *def = "";
int id_len;
int maxlen = 0;
@@ -2577,12 +2641,17 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
PyObject *get_cb = NULL;
PyObject *set_cb = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|sssiO!sOOO:StringProperty",
- (char **)kwlist, &id, &id_len,
- &name, &description, &def,
- &maxlen, &PySet_Type, &pyopts, &pysubtype,
- &update_cb, &get_cb, &set_cb))
+ static const char *_keywords[] = {
+ "attr", "name", "description", "default",
+ "maxlen", "options", "subtype", "update", "get", "set", NULL,
+ };
+ static _PyArg_Parser _parser = {"s#|sssiO!sOOO:StringProperty", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &id, &id_len,
+ &name, &description, &def,
+ &maxlen, &PySet_Type, &pyopts, &pysubtype,
+ &update_cb, &get_cb, &set_cb))
{
return NULL;
}
@@ -2637,7 +2706,8 @@ PyDoc_STRVAR(BPy_EnumProperty_doc,
" :icon: An icon string identifier or integer icon value\n"
" (e.g. returned by :class:`bpy.types.UILayout.icon`)\n"
" :number: Unique value used as the identifier for this item (stored in file data).\n"
-" Use when the identifier may need to change.\n"
+" Use when the identifier may need to change. If the *ENUM_FLAG* option is used,\n"
+" the values are bitmasks and should be powers of two.\n"
"\n"
" When an item only contains 4 items they define ``(identifier, name, description, number)``.\n"
"\n"
@@ -2671,8 +2741,6 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
BPY_PROPDEF_HEAD(EnumProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "items", "name", "description", "default",
- "options", "update", "get", "set", NULL};
const char *id = NULL, *name = NULL, *description = "";
PyObject *def = NULL;
int id_len;
@@ -2687,12 +2755,17 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *get_cb = NULL;
PyObject *set_cb = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#O|ssOO!OOO:EnumProperty",
- (char **)kwlist, &id, &id_len,
- &items, &name, &description,
- &def, &PySet_Type, &pyopts,
- &update_cb, &get_cb, &set_cb))
+ static const char *_keywords[] = {
+ "attr", "items", "name", "description", "default",
+ "options", "update", "get", "set", NULL,
+ };
+ static _PyArg_Parser _parser = {"s#O|ssOO!OOO:EnumProperty", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &id, &id_len,
+ &items, &name, &description,
+ &def, &PySet_Type, &pyopts,
+ &update_cb, &get_cb, &set_cb))
{
return NULL;
}
@@ -2772,7 +2845,7 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
Py_RETURN_NONE;
}
-static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix)
+StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix)
{
StructRNA *srna;
@@ -2782,25 +2855,18 @@ static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix
PyObject *msg = PyC_ExceptionBuffer();
const char *msg_char = _PyUnicode_AsString(msg);
PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup, failed with: %s",
+ "%.200s expected an RNA type, failed with: %s",
error_prefix, msg_char);
Py_DECREF(msg);
}
else {
PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup, failed with type '%s'",
+ "%.200s expected an RNA type, failed with type '%s'",
error_prefix, Py_TYPE(value)->tp_name);
}
return NULL;
}
- if (!RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
- PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup",
- error_prefix);
- return NULL;
- }
-
return srna;
}
@@ -2809,6 +2875,7 @@ PyDoc_STRVAR(BPy_PointerProperty_doc,
"name=\"\", "
"description=\"\", "
"options={'ANIMATABLE'}, "
+ "poll=None, "
"update=None)\n"
"\n"
" Returns a new pointer property definition.\n"
@@ -2819,14 +2886,13 @@ BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_UPDATE_DOC
);
-static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
+PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
BPY_PROPDEF_HEAD(PointerProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "type", "name", "description", "options", "update", NULL};
const char *id = NULL, *name = NULL, *description = "";
int id_len;
PropertyRNA *prop;
@@ -2834,33 +2900,51 @@ static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *k
PyObject *type = Py_None;
PyObject *pyopts = NULL;
int opts = 0;
- PyObject *update_cb = NULL;
-
- if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#O|ssO!O:PointerProperty",
- (char **)kwlist, &id, &id_len,
- &type, &name, &description,
- &PySet_Type, &pyopts,
- &update_cb))
+ PyObject *update_cb = NULL, *poll_cb = NULL;
+
+ static const char *_keywords[] = {
+ "attr", "type", "name", "description", "options", "poll", "update", NULL,
+ };
+ static _PyArg_Parser _parser = {"s#O|ssO!OO:PointerProperty", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &id, &id_len,
+ &type, &name, &description,
+ &PySet_Type, &pyopts,
+ &poll_cb, &update_cb))
{
return NULL;
}
BPY_PROPDEF_CHECK(PointerProperty, property_flag_items);
- ptype = pointer_type_from_py(type, "PointerProperty(...):");
+ ptype = pointer_type_from_py(type, "PointerProperty(...)");
if (!ptype)
return NULL;
-
+ if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup) && !RNA_struct_is_ID(ptype)) {
+ PyErr_Format(PyExc_TypeError,
+ "PointerProperty(...) expected an RNA type derived from %.200s or %.200s",
+ RNA_struct_ui_name(&RNA_ID), RNA_struct_ui_name(&RNA_PropertyGroup));
+ return NULL;
+ }
if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
return NULL;
}
-
+ if (bpy_prop_callback_check(poll_cb, "poll", 2) == -1) {
+ return NULL;
+ }
prop = RNA_def_pointer_runtime(srna, id, ptype, name ? name : id, description);
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+
+ if (RNA_struct_idprops_contains_datablock(ptype)) {
+ if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
+ RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES);
+ }
+ }
bpy_prop_callback_assign_update(prop, update_cb);
+ bpy_prop_callback_assign_pointer(prop, poll_cb);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
@@ -2879,27 +2963,30 @@ BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC
);
-static PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
+PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
BPY_PROPDEF_HEAD(CollectionProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "type", "name", "description", "options", NULL};
- const char *id = NULL, *name = NULL, *description = "";
int id_len;
+ const char *id = NULL, *name = NULL, *description = "";
PropertyRNA *prop;
StructRNA *ptype;
PyObject *type = Py_None;
PyObject *pyopts = NULL;
int opts = 0;
- if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#O|ssO!:CollectionProperty",
- (char **)kwlist, &id, &id_len,
- &type, &name, &description,
- &PySet_Type, &pyopts))
+ static const char *_keywords[] = {
+ "attr", "type", "name", "description", "options", NULL,
+ };
+ static _PyArg_Parser _parser = {"s#O|ssO!:CollectionProperty", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &id, &id_len,
+ &type, &name, &description,
+ &PySet_Type, &pyopts))
{
return NULL;
}
@@ -2910,17 +2997,30 @@ static PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject
if (!ptype)
return NULL;
+ if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup)) {
+ PyErr_Format(PyExc_TypeError,
+ "CollectionProperty(...) expected an RNA type derived from %.200s",
+ RNA_struct_ui_name(&RNA_ID), RNA_struct_ui_name(&RNA_PropertyGroup));
+ return NULL;
+ }
+
prop = RNA_def_collection_runtime(srna, id, ptype, name ? name : id, description);
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+
+ if (RNA_struct_idprops_contains_datablock(ptype)) {
+ if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
+ RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES);
+ }
+ }
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(BPy_RemoveProperty_doc,
-".. function:: RemoveProperty(cls, attr="")\n"
+".. function:: RemoveProperty(cls, attr)\n"
"\n"
" Removes a dynamically defined property.\n"
"\n"
@@ -2958,13 +3058,15 @@ static PyObject *BPy_RemoveProperty(PyObject *self, PyObject *args, PyObject *kw
return NULL;
}
else {
- static const char *kwlist[] = {"attr", NULL};
-
const char *id = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s:RemoveProperty",
- (char **)kwlist, &id))
+ static const char *_keywords[] = {
+ "attr", NULL,
+ };
+ static _PyArg_Parser _parser = {"s:RemoveProperty", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &id))
{
return NULL;
}
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index c9934ca0cf3..614c1b4b708 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -30,6 +30,10 @@
PyObject *BPY_rna_props(void);
+PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw);
+StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix);
+
#define PYRNA_STACK_ARRAY 32
#endif
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index ab523e03f4d..398d2631f6c 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -70,6 +70,8 @@
#include "BKE_report.h"
#include "BKE_idprop.h"
+/* only for types */
+#include "BKE_node.h"
#include "../generic/idprop_py_api.h" /* for IDprop lookups */
#include "../generic/py_capi_utils.h"
@@ -806,7 +808,7 @@ static PyObject *pyrna_struct_richcmp(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
@@ -836,7 +838,7 @@ static PyObject *pyrna_prop_richcmp(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
@@ -1395,7 +1397,7 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
}
else {
EnumPropertyItem *enum_item;
- bool free = false;
+ bool free;
/* don't throw error here, can't trust blender 100% to give the
* right values, python code should not generate error for that */
@@ -1404,6 +1406,9 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
ret = PyUnicode_FromString(enum_item->identifier);
}
else {
+ if (free) {
+ MEM_freeN(enum_item);
+ }
RNA_property_enum_items(NULL, ptr, prop, &enum_item, NULL, &free);
/* Do not print warning in case of DummyRNA_NULL_items, this one will never match any value... */
@@ -1636,11 +1641,11 @@ static int pyrna_py_to_prop(
/* prefer not to have an exception here
* however so many poll functions return None or a valid Object.
* its a hassle to convert these into a bool before returning, */
- if (RNA_property_flag(prop) & PROP_OUTPUT) {
+ if (RNA_parameter_flag(prop) & PARM_OUTPUT) {
param = PyObject_IsTrue(value);
}
else {
- param = PyLong_AsLong(value);
+ param = PyC_Long_AsI32(value);
if (UNLIKELY(param & ~1)) { /* only accept 0/1 */
param = -1; /* error out below */
@@ -1824,6 +1829,7 @@ static int pyrna_py_to_prop(
StructRNA *ptr_type = RNA_property_pointer_type(ptr, prop);
int flag = RNA_property_flag(prop);
+ int flag_parameter = RNA_parameter_flag(prop);
/* this is really nasty!, so we can fake the operator having direct properties eg:
* layout.prop(self, "filepath")
@@ -1900,7 +1906,7 @@ static int pyrna_py_to_prop(
bool raise_error = false;
if (data) {
- if (flag & PROP_RNAPTR) {
+ if (flag_parameter & PARM_RNAPTR) {
if (flag & PROP_THICK_WRAP) {
if (value == Py_None)
memset(data, 0, sizeof(PointerRNA));
@@ -1933,16 +1939,10 @@ static int pyrna_py_to_prop(
}
else {
/* data == NULL, assign to RNA */
- if (value == Py_None) {
- PointerRNA valueptr = {{NULL}};
- RNA_property_pointer_set(ptr, prop, valueptr);
- }
- else if (RNA_struct_is_a(param->ptr.type, ptr_type)) {
- RNA_property_pointer_set(ptr, prop, param->ptr);
- }
- else {
+ if (value == Py_None || RNA_struct_is_a(param->ptr.type, ptr_type))
+ RNA_property_pointer_set(ptr, prop, value == Py_None ? PointerRNA_NULL : param->ptr);
+ else
raise_error = true;
- }
}
if (raise_error) {
@@ -2081,10 +2081,10 @@ static int pyrna_py_to_prop_array_index(BPy_PropertyArrayRNA *self, int index, P
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
{
- int param = PyLong_AsLong(value);
+ int param = PyC_Long_AsBool(value);
- if (param < 0 || param > 1) {
- PyErr_SetString(PyExc_TypeError, "expected True/False or 0/1");
+ if (param == -1) {
+ /* error is set */
ret = -1;
}
else {
@@ -2094,7 +2094,7 @@ static int pyrna_py_to_prop_array_index(BPy_PropertyArrayRNA *self, int index, P
}
case PROP_INT:
{
- int param = PyLong_AsLong(value);
+ int param = PyC_Long_AsI32(value);
if (param == -1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "expected an int type");
ret = -1;
@@ -2714,7 +2714,7 @@ static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject
Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
return NULL;
- return pyrna_prop_array_subscript_int(self, PyLong_AsLong(key));
+ return pyrna_prop_array_subscript_int(self, i);
}
else if (PySlice_Check(key)) {
Py_ssize_t step = 1;
@@ -3276,6 +3276,20 @@ static int pyrna_struct_ass_subscript(BPy_StructRNA *self, PyObject *key, PyObje
return -1;
}
+ if (value && BPy_StructRNA_Check(value)) {
+ BPy_StructRNA *val = (BPy_StructRNA *)value;
+ if (val && self->ptr.type && val->ptr.type) {
+ if (!RNA_struct_idprops_datablock_allowed(self->ptr.type) &&
+ RNA_struct_idprops_contains_datablock(val->ptr.type))
+ {
+ PyErr_SetString(
+ PyExc_TypeError,
+ "bpy_struct[key] = val: datablock id properties not supported for this type");
+ return -1;
+ }
+ }
+ }
+
return BPy_Wrap_SetMapItem(group, key, value);
}
@@ -3695,6 +3709,110 @@ static PyObject *pyrna_struct_type_recast(BPy_StructRNA *self)
return pyrna_struct_CreatePyObject(&r_ptr);
}
+/**
+ * \note Return value is borrowed, caller must incref.
+ */
+static PyObject *pyrna_struct_bl_rna_find_subclass_recursive(PyObject *cls, const char *id)
+{
+ PyObject *ret_test = NULL;
+ PyObject *subclasses = ((PyTypeObject *)cls)->tp_subclasses;
+ if (subclasses) {
+ /* Unfortunately we can't use the dict key because Python class names
+ * don't match the bl_idname used internally. */
+ BLI_assert(PyDict_CheckExact(subclasses));
+ PyObject *key = NULL;
+ Py_ssize_t pos = 0;
+ PyObject *value = NULL;
+ while (PyDict_Next(subclasses, &pos, &key, &value)) {
+ BLI_assert(PyWeakref_CheckRef(value));
+ PyObject *subcls = PyWeakref_GET_OBJECT(value);
+ if (subcls != Py_None) {
+ BPy_StructRNA *py_srna = (BPy_StructRNA *)PyDict_GetItem(
+ ((PyTypeObject *)subcls)->tp_dict, bpy_intern_str_bl_rna);
+ if (py_srna) {
+ StructRNA *srna = py_srna->ptr.data;
+ if (STREQ(id, RNA_struct_identifier(srna))) {
+ ret_test = subcls;
+ break;
+ }
+ }
+ ret_test = pyrna_struct_bl_rna_find_subclass_recursive(subcls, id);
+ if (ret_test) {
+ break;
+ }
+ }
+ }
+ }
+ return ret_test;
+}
+
+PyDoc_STRVAR(pyrna_struct_bl_rna_get_subclass_py_doc,
+".. classmethod:: bl_rna_get_subclass_py(id, default=None)\n"
+"\n"
+" :arg id: The RNA type identifier.\n"
+" :type id: string\n"
+" :return: The class or default when not found.\n"
+" :rtype: type\n"
+);
+static PyObject *pyrna_struct_bl_rna_get_subclass_py(PyObject *cls, PyObject *args)
+{
+ char *id;
+ PyObject *ret_default = Py_None;
+
+ if (!PyArg_ParseTuple(args, "s|O:bl_rna_get_subclass_py", &id, &ret_default)) {
+ return NULL;
+ }
+ PyObject *ret = pyrna_struct_bl_rna_find_subclass_recursive(cls, id);
+ if (ret == NULL) {
+ ret = ret_default;
+ }
+ return Py_INCREF_RET(ret);
+}
+
+PyDoc_STRVAR(pyrna_struct_bl_rna_get_subclass_doc,
+".. classmethod:: bl_rna_get_subclass(id, default=None)\n"
+"\n"
+" :arg id: The RNA type identifier.\n"
+" :type id: string\n"
+" :return: The RNA type or default when not found.\n"
+" :rtype: :class:`bpy.types.Struct` subclass\n"
+);
+static PyObject *pyrna_struct_bl_rna_get_subclass(PyObject *cls, PyObject *args)
+{
+ char *id;
+ PyObject *ret_default = Py_None;
+
+ if (!PyArg_ParseTuple(args, "s|O:bl_rna_get_subclass", &id, &ret_default)) {
+ return NULL;
+ }
+
+
+ const BPy_StructRNA *py_srna = (BPy_StructRNA *)PyDict_GetItem(((PyTypeObject *)cls)->tp_dict, bpy_intern_str_bl_rna);
+ if (py_srna == NULL) {
+ PyErr_SetString(PyExc_ValueError, "Not a registered class");
+ return NULL;
+
+ }
+ const StructRNA *srna_base = py_srna->ptr.data;
+
+ PointerRNA ptr;
+ if (srna_base == &RNA_Node) {
+ bNodeType *nt = nodeTypeFind(id);
+ if (nt) {
+ RNA_pointer_create(NULL, &RNA_Struct, nt->ext.srna, &ptr);
+ return pyrna_struct_CreatePyObject(&ptr);
+ }
+ }
+ else {
+ /* TODO, panels, menus etc. */
+ PyErr_Format(PyExc_ValueError, "Class type \"%.200s\" not supported",
+ RNA_struct_identifier(srna_base));
+ return NULL;
+ }
+
+ return Py_INCREF_RET(ret_default);
+}
+
static void pyrna_dir_members_py__add_keys(PyObject *list, PyObject *dict)
{
PyObject *list_tmp;
@@ -4993,6 +5111,8 @@ static struct PyMethodDef pyrna_struct_methods[] = {
{"path_resolve", (PyCFunction)pyrna_struct_path_resolve, METH_VARARGS, pyrna_struct_path_resolve_doc},
{"path_from_id", (PyCFunction)pyrna_struct_path_from_id, METH_VARARGS, pyrna_struct_path_from_id_doc},
{"type_recast", (PyCFunction)pyrna_struct_type_recast, METH_NOARGS, pyrna_struct_type_recast_doc},
+ {"bl_rna_get_subclass_py", (PyCFunction) pyrna_struct_bl_rna_get_subclass_py, METH_VARARGS | METH_CLASS, pyrna_struct_bl_rna_get_subclass_py_doc},
+ {"bl_rna_get_subclass", (PyCFunction) pyrna_struct_bl_rna_get_subclass, METH_VARARGS | METH_CLASS, pyrna_struct_bl_rna_get_subclass_doc},
{"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL},
/* experimental */
@@ -5116,6 +5236,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat
PyObject *ret;
const int type = RNA_property_type(prop);
const int flag = RNA_property_flag(prop);
+ const int flag_parameter = RNA_parameter_flag(prop);
if (RNA_property_array_check(prop)) {
int a, len;
@@ -5158,7 +5279,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat
ret = Matrix_CreatePyObject(data, 3, 3, NULL);
break;
}
- /* fall-through */
+ ATTR_FALLTHROUGH;
#endif
default:
ret = PyTuple_New(len);
@@ -5233,7 +5354,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat
PointerRNA newptr;
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
- if (flag & PROP_RNAPTR) {
+ if (flag_parameter & PARM_RNAPTR) {
/* in this case we get the full ptr */
newptr = *(PointerRNA *)data;
}
@@ -5315,7 +5436,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
ParameterIterator iter;
PropertyRNA *parm;
PyObject *ret, *item;
- int i, pyargs_len, pykw_len, parms_len, ret_len, flag, err = 0, kw_tot = 0;
+ int i, pyargs_len, pykw_len, parms_len, ret_len, flag_parameter, err = 0, kw_tot = 0;
bool kw_arg;
PropertyRNA *pret_single = NULL;
@@ -5380,10 +5501,10 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
/* parse function parameters */
for (i = 0; iter.valid && err == 0; RNA_parameter_list_next(&iter)) {
parm = iter.parm;
- flag = RNA_property_flag(parm);
+ flag_parameter = RNA_parameter_flag(parm);
/* only useful for single argument returns, we'll need another list loop for multiple */
- if (flag & PROP_OUTPUT) {
+ if (flag_parameter & PARM_OUTPUT) {
ret_len++;
if (pret_single == NULL) {
pret_single = parm;
@@ -5414,7 +5535,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
i++; /* current argument */
if (item == NULL) {
- if (flag & PROP_REQUIRED) {
+ if (flag_parameter & PARM_REQUIRED) {
PyErr_Format(PyExc_TypeError,
"%.200s.%.200s(): required parameter \"%.200s\" not specified",
RNA_struct_identifier(self_ptr->type),
@@ -5514,7 +5635,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
RNA_parameter_list_begin(&parms, &iter);
for (; iter.valid; RNA_parameter_list_next(&iter)) {
parm = iter.parm;
- if (RNA_property_flag(parm) & PROP_OUTPUT)
+ if (RNA_parameter_flag(parm) & PARM_OUTPUT)
continue;
BLI_dynstr_appendf(good_args, first ? "%s" : ", %s", RNA_property_identifier(parm));
@@ -5561,9 +5682,8 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
for (; iter.valid; RNA_parameter_list_next(&iter)) {
parm = iter.parm;
- flag = RNA_property_flag(parm);
- if (flag & PROP_OUTPUT)
+ if (RNA_parameter_flag(parm) & PARM_OUTPUT)
PyTuple_SET_ITEM(ret, i++, pyrna_param_to_py(&funcptr, parm, iter.data));
}
@@ -5683,7 +5803,7 @@ PyTypeObject pyrna_struct_meta_idprop_Type = {
NULL, /* struct PyMethodDef *tp_methods; */
NULL, /* struct PyMemberDef *tp_members; */
NULL, /* struct PyGetSetDef *tp_getset; */
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
NULL, /* defer assignment */
#else
&PyType_Type, /* struct _typeobject *tp_base; */
@@ -6258,7 +6378,7 @@ static PyTypeObject pyrna_prop_collection_iter_Type = {
NULL, /* reprfunc tp_str; */
/* will only use these if this is a subtype of a py class */
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
NULL, /* defer assignment */
#else
PyObject_GenericGetAttr, /* getattrofunc tp_getattro; */
@@ -6291,7 +6411,7 @@ static PyTypeObject pyrna_prop_collection_iter_Type = {
#endif
/*** Added in release 2.2 ***/
/* Iterators */
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
NULL, /* defer assignment */
#else
PyObject_SelfIter, /* getiterfunc tp_iter; */
@@ -6744,7 +6864,7 @@ PyObject *pyrna_id_CreatePyObject(ID *id)
bool pyrna_id_FromPyObject(PyObject *obj, ID **id)
{
- if (BPy_StructRNA_Check(obj) && (RNA_struct_is_ID(((BPy_StructRNA *)obj)->ptr.type))) {
+ if (pyrna_id_CheckPyObject(obj)) {
*id = ((BPy_StructRNA *)obj)->ptr.id.data;
return true;
}
@@ -6754,6 +6874,11 @@ bool pyrna_id_FromPyObject(PyObject *obj, ID **id)
}
}
+bool pyrna_id_CheckPyObject(PyObject *obj)
+{
+ return BPy_StructRNA_Check(obj) && (RNA_struct_is_ID(((BPy_StructRNA *) obj)->ptr.type));
+}
+
void BPY_rna_init(void)
{
#ifdef USE_MATHUTILS /* register mathutils callbacks, ok to run more than once. */
@@ -6762,7 +6887,7 @@ void BPY_rna_init(void)
#endif
/* for some reason MSVC complains of these */
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
pyrna_struct_meta_idprop_Type.tp_base = &PyType_Type;
pyrna_prop_collection_iter_Type.tp_iter = PyObject_SelfIter;
@@ -6910,15 +7035,7 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self)
RNA_PROP_BEGIN (&self->ptr, itemptr, self->prop)
{
StructRNA *srna = itemptr.data;
- StructRNA *srna_base = RNA_struct_base(itemptr.data);
- /* skip own operators, these double up [#29666] */
- if (srna_base == &RNA_Operator) {
- /* do nothing */
- }
- else {
- /* add to python list */
- PyList_APPEND(ret, PyUnicode_FromString(RNA_struct_identifier(srna)));
- }
+ PyList_APPEND(ret, PyUnicode_FromString(RNA_struct_identifier(srna)));
}
RNA_PROP_END;
@@ -7088,6 +7205,21 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item
args_fake = PyTuple_New(1);
PyTuple_SET_ITEM(args_fake, 0, py_srna_cobject);
+ PyObject *type = PyDict_GetItemString(py_kw, "type");
+ StructRNA *type_srna = srna_from_self(type, "");
+ if (type_srna) {
+ if (!RNA_struct_idprops_datablock_allowed(srna) &&
+ (*(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) == BPy_PointerProperty ||
+ *(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) == BPy_CollectionProperty) &&
+ RNA_struct_idprops_contains_datablock(type_srna))
+ {
+ PyErr_Format(PyExc_ValueError,
+ "bpy_struct \"%.200s\" doesn't support datablock properties \n",
+ RNA_struct_identifier(srna));
+ return -1;
+ }
+ }
+
py_ret = PyObject_Call(py_func, args_fake, py_kw);
if (py_ret) {
@@ -7216,8 +7348,8 @@ static int rna_function_arg_count(FunctionRNA *func, int *min_count)
for (link = lb->first; link; link = link->next) {
parm = (PropertyRNA *)link;
- if (!(RNA_property_flag(parm) & PROP_OUTPUT)) {
- if (!done_min_count && (RNA_property_flag(parm) & PROP_PYFUNC_OPTIONAL)) {
+ if (!(RNA_parameter_flag(parm) & PARM_OUTPUT)) {
+ if (!done_min_count && (RNA_parameter_flag(parm) & PARM_PYFUNC_OPTIONAL)) {
/* From now on, following parameters are optional in py func */
if (min_count)
*min_count = count;
@@ -7236,15 +7368,12 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
{
const ListBase *lb;
Link *link;
- FunctionRNA *func;
- PropertyRNA *prop;
const char *class_type = RNA_struct_identifier(srna);
StructRNA *srna_base = RNA_struct_base(srna);
PyObject *py_class = (PyObject *)py_data;
PyObject *base_class = RNA_struct_py_type_get(srna);
PyObject *item;
- int i, flag, arg_count, func_arg_count, func_arg_min_count = 0;
- bool is_staticmethod;
+ int i, arg_count, func_arg_count, func_arg_min_count = 0;
const char *py_class_name = ((PyTypeObject *)py_class)->tp_name; /* __name__ */
if (srna_base) {
@@ -7265,9 +7394,12 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
lb = RNA_struct_type_functions(srna);
i = 0;
for (link = lb->first; link; link = link->next) {
- func = (FunctionRNA *)link;
- flag = RNA_function_flag(func);
- is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
+ FunctionRNA *func = (FunctionRNA *)link;
+ const int flag = RNA_function_flag(func);
+ /* TODO(campbell): this is used for classmethod's too,
+ * even though class methods should have 'FUNC_USE_SELF_TYPE' set, see Operator.poll for eg.
+ * Keep this as-is since its working but we should be using 'FUNC_USE_SELF_TYPE' for many functions. */
+ const bool is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
if (!(flag & FUNC_REGISTER))
continue;
@@ -7293,7 +7425,8 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
if (is_staticmethod) {
if (PyMethod_Check(item) == 0) {
PyErr_Format(PyExc_TypeError,
- "expected %.200s, %.200s class \"%.200s\" attribute to be a method, not a %.200s",
+ "expected %.200s, %.200s class \"%.200s\" "
+ "attribute to be a static/class method, not a %.200s",
class_type, py_class_name, RNA_function_identifier(func), Py_TYPE(item)->tp_name);
return -1;
}
@@ -7302,7 +7435,8 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
else {
if (PyFunction_Check(item) == 0) {
PyErr_Format(PyExc_TypeError,
- "expected %.200s, %.200s class \"%.200s\" attribute to be a function, not a %.200s",
+ "expected %.200s, %.200s class \"%.200s\" "
+ "attribute to be a function, not a %.200s",
class_type, py_class_name, RNA_function_identifier(func), Py_TYPE(item)->tp_name);
return -1;
}
@@ -7314,7 +7448,7 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
arg_count = ((PyCodeObject *)PyFunction_GET_CODE(item))->co_argcount;
/* note, the number of args we check for and the number of args we give to
- * @staticmethods are different (quirk of python),
+ * '@staticmethods' are different (quirk of python),
* this is why rna_function_arg_count() doesn't return the value -1*/
if (is_staticmethod) {
func_arg_count++;
@@ -7345,8 +7479,8 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
lb = RNA_struct_type_properties(srna);
for (link = lb->first; link; link = link->next) {
const char *identifier;
- prop = (PropertyRNA *)link;
- flag = RNA_property_flag(prop);
+ PropertyRNA *prop = (PropertyRNA *)link;
+ const int flag = RNA_property_flag(prop);
if (!(flag & PROP_REGISTER))
continue;
@@ -7575,10 +7709,9 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
/* parse function parameters */
for (; iter.valid; RNA_parameter_list_next(&iter)) {
parm = iter.parm;
- flag = RNA_property_flag(parm);
/* only useful for single argument returns, we'll need another list loop for multiple */
- if (flag & PROP_OUTPUT) {
+ if (RNA_parameter_flag(parm) & PARM_OUTPUT) {
ret_len++;
if (pret_single == NULL) {
pret_single = parm;
@@ -7678,10 +7811,9 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
/* parse function parameters */
for (i = 0; iter.valid; RNA_parameter_list_next(&iter)) {
parm = iter.parm;
- flag = RNA_property_flag(parm);
/* only useful for single argument returns, we'll need another list loop for multiple */
- if (flag & PROP_OUTPUT) {
+ if (RNA_parameter_flag(parm) & PARM_OUTPUT) {
err = pyrna_py_to_prop(&funcptr, parm, iter.data,
PyTuple_GET_ITEM(ret, i++),
"calling class function:");
@@ -7967,7 +8099,7 @@ static int pyrna_srna_contains_pointer_prop_srna(
for (link = lb->first; link; link = link->next) {
prop = (PropertyRNA *)link;
- if (RNA_property_type(prop) == PROP_POINTER && !(RNA_property_flag(prop) & PROP_BUILTIN)) {
+ if (RNA_property_type(prop) == PROP_POINTER && !RNA_property_builtin(prop)) {
PointerRNA tptr;
RNA_pointer_create(NULL, &RNA_Struct, srna_props, &tptr);
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index e38d4f095d6..605f79b1ad8 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -179,6 +179,7 @@ PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop);
/* extern'd by other modules which don't deal closely with RNA */
PyObject *pyrna_id_CreatePyObject(struct ID *id);
bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id);
+bool pyrna_id_CheckPyObject(PyObject *obj);
/* operators also need this to set args */
int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const bool all_args, const char *error_prefix);
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 92931eb8090..8a0130babd5 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -36,12 +36,15 @@
#include "DNA_scene_types.h"
#include "DNA_anim_types.h"
+
#include "ED_keyframing.h"
+#include "ED_keyframes_edit.h"
#include "BKE_report.h"
#include "BKE_context.h"
#include "BKE_animsys.h"
#include "BKE_fcurve.h"
+#include "BKE_idcode.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
@@ -223,9 +226,47 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
{
return NULL;
}
+ else if (self->ptr.type == &RNA_NlaStrip) {
+ /* Handle special properties for NLA Strips, whose F-Curves are stored on the
+ * strips themselves. These are stored separately or else the properties will
+ * not have any effect.
+ */
+ ReportList reports;
+ short result = 0;
+
+ PointerRNA ptr = self->ptr;
+ PropertyRNA *prop = NULL;
+ const char *prop_name;
+
+ BKE_reports_init(&reports, RPT_STORE);
+
+ /* Retrieve the property identifier from the full path, since we can't get it any other way */
+ prop_name = strrchr(path_full, '.');
+ if ((prop_name >= path_full) &&
+ (prop_name + 1 < path_full + strlen(path_full)))
+ {
+ prop = RNA_struct_find_property(&ptr, prop_name + 1);
+ }
+
+ if (prop) {
+ NlaStrip *strip = (NlaStrip *)ptr.data;
+ FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
+
+ result = insert_keyframe_direct(&reports, ptr, prop, fcu, cfra, keytype, options);
+ }
+ else {
+ BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
+ }
+ MEM_freeN((void *)path_full);
+
+ if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
+ return NULL;
+
+ return PyBool_FromLong(result);
+ }
else {
- short result;
ReportList reports;
+ short result;
BKE_reports_init(&reports, RPT_STORE);
@@ -272,6 +313,67 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb
{
return NULL;
}
+ else if (self->ptr.type == &RNA_NlaStrip) {
+ /* Handle special properties for NLA Strips, whose F-Curves are stored on the
+ * strips themselves. These are stored separately or else the properties will
+ * not have any effect.
+ */
+ ReportList reports;
+ short result = 0;
+
+ PointerRNA ptr = self->ptr;
+ PropertyRNA *prop = NULL;
+ const char *prop_name;
+
+ BKE_reports_init(&reports, RPT_STORE);
+
+ /* Retrieve the property identifier from the full path, since we can't get it any other way */
+ prop_name = strrchr(path_full, '.');
+ if ((prop_name >= path_full) &&
+ (prop_name + 1 < path_full + strlen(path_full)))
+ {
+ prop = RNA_struct_find_property(&ptr, prop_name + 1);
+ }
+
+ if (prop) {
+ ID *id = ptr.id.data;
+ NlaStrip *strip = (NlaStrip *)ptr.data;
+ FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
+
+ BLI_assert(fcu != NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */
+
+ if (BKE_fcurve_is_protected(fcu)) {
+ BKE_reportf(&reports, RPT_WARNING,
+ "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
+ strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2);
+ }
+ else {
+ /* remove the keyframe directly
+ * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve,
+ * and delete_keyframe() expects the FCurve to be part of an action
+ */
+ bool found = false;
+ int i;
+
+ /* try to find index of beztriple to get rid of */
+ i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
+ if (found) {
+ /* delete the key at the index (will sanity check + do recalc afterwards) */
+ delete_fcurve_key(fcu, i, 1);
+ result = true;
+ }
+ }
+ }
+ else {
+ BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
+ }
+ MEM_freeN((void *)path_full);
+
+ if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
+ return NULL;
+
+ return PyBool_FromLong(result);
+ }
else {
short result;
ReportList reports;
diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c
index 38931cd85de..3e147d29c90 100644
--- a/source/blender/python/intern/bpy_rna_array.c
+++ b/source/blender/python/intern/bpy_rna_array.c
@@ -38,6 +38,8 @@
#include "RNA_access.h"
+#include "../generic/py_capi_utils.h"
+
#define USE_MATHUTILS
#ifdef USE_MATHUTILS
@@ -550,7 +552,7 @@ static void py_to_float(const struct ItemConvertArgData *arg, PyObject *py, char
static void py_to_int(const struct ItemConvertArgData *arg, PyObject *py, char *data)
{
const int *range = arg->int_data.range;
- int value = (int)PyLong_AsLong(py);
+ int value = PyC_Long_AsI32(py);
CLAMP(value, range[0], range[1]);
*(int *)data = value;
}
diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c
index b4c0de51c04..1135ba121e3 100644
--- a/source/blender/python/intern/bpy_rna_driver.c
+++ b/source/blender/python/intern/bpy_rna_driver.c
@@ -63,7 +63,15 @@ PyObject *pyrna_driver_get_variable_value(
}
else {
/* object & property */
- driver_arg = pyrna_prop_to_py(&ptr, prop);
+ PropertyType type = RNA_property_type(prop);
+ if (type == PROP_ENUM) {
+ /* Note that enum's are converted to strings by default,
+ * we want to avoid that, see: T52213 */
+ driver_arg = PyLong_FromLong(RNA_property_enum_get(&ptr, prop));
+ }
+ else {
+ driver_arg = pyrna_prop_to_py(&ptr, prop);
+ }
}
}
else {
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index 1037c83815c..8def52dc8fb 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -163,7 +163,6 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *
Main *bmain = G.main; /* XXX Ugly, but should work! */
#endif
- static const char *kwlist[] = {"subset", "key_types", "value_types", NULL};
PyObject *subset = NULL;
PyObject *key_types = NULL;
@@ -173,9 +172,10 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *
PyObject *ret = NULL;
-
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds, "|O$O!O!:user_map", (char **)kwlist,
+ static const char *_keywords[] = {"subset", "key_types", "value_types", NULL};
+ static _PyArg_Parser _parser = {"|O$O!O!:user_map", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser,
&subset,
&PySet_Type, &key_types,
&PySet_Type, &val_types))
@@ -263,7 +263,7 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *
}
data_cb.id_curr = id;
- BKE_library_foreach_ID_link(id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_NOP);
+ BKE_library_foreach_ID_link(NULL, id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_CB_NOP);
if (data_cb.py_id_curr) {
Py_DECREF(data_cb.py_id_curr);
diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h
index 63cb7920bd1..6000bf94aef 100644
--- a/source/blender/python/intern/bpy_util.h
+++ b/source/blender/python/intern/bpy_util.h
@@ -27,8 +27,8 @@
#ifndef __BPY_UTIL_H__
#define __BPY_UTIL_H__
-#if PY_VERSION_HEX < 0x03050000
-# error "Python 3.5 or greater is required, you'll need to update your python."
+#if PY_VERSION_HEX < 0x03060000
+# error "Python 3.6 or greater is required, you'll need to update your python."
#endif
struct EnumPropertyItem;
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index 974d7c5549c..0ef689d1a5a 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -174,8 +174,6 @@ PyDoc_STRVAR(bpyunits_to_value_doc,
);
static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- static const char *kwlist[] = {"unit_system", "unit_category", "str_input", "str_ref_unit", NULL};
-
char *usys_str = NULL, *ucat_str = NULL, *inpt = NULL, *uref = NULL;
const float scale = 1.0f;
@@ -185,8 +183,13 @@ static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObj
int usys, ucat;
PyObject *ret;
- if (!PyArg_ParseTupleAndKeywords(args, kw, "sss#|z:bpy.utils.units.to_value", (char **)kwlist,
- &usys_str, &ucat_str, &inpt, &str_len, &uref))
+ static const char *_keywords[] = {
+ "unit_system", "unit_category", "str_input", "str_ref_unit", NULL,
+ };
+ static _PyArg_Parser _parser = {"sss#|z:to_value", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &usys_str, &ucat_str, &inpt, &str_len, &uref))
{
return NULL;
}
@@ -201,7 +204,7 @@ static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObj
bUnit_ReplaceString(str, (int)str_len, uref, scale, usys, ucat);
- if (!PyC_RunString_AsNumber(str, &result, "<bpy_units_api>")) {
+ if (!PyC_RunString_AsNumber(str, "<bpy_units_api>", &result)) {
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
@@ -244,9 +247,6 @@ PyDoc_STRVAR(bpyunits_to_string_doc,
);
static PyObject *bpyunits_to_string(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- static const char *kwlist[] = {"unit_system", "unit_category", "value",
- "precision", "split_unit", "compatible_unit", NULL};
-
char *usys_str = NULL, *ucat_str = NULL;
double value = 0.0;
int precision = 3;
@@ -254,9 +254,13 @@ static PyObject *bpyunits_to_string(PyObject *UNUSED(self), PyObject *args, PyOb
int usys, ucat;
- if (!PyArg_ParseTupleAndKeywords(
- args, kw,
- "ssd|iO&O&:bpy.utils.units.to_string", (char **)kwlist,
+ static const char *_keywords[] = {
+ "unit_system", "unit_category", "value",
+ "precision", "split_unit", "compatible_unit", NULL,
+ };
+ static _PyArg_Parser _parser = {"ssd|iO&O&:to_string", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
&usys_str, &ucat_str, &value, &precision,
PyC_ParseBool, &split_unit,
PyC_ParseBool, &compatible_unit))
diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c
index 50dd4618166..60ce00c583e 100644
--- a/source/blender/python/intern/gpu.c
+++ b/source/blender/python/intern/gpu.c
@@ -138,6 +138,7 @@ static PyObject *PyInit_gpu(void)
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_EMIT);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_AMB);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_ALPHA);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_MIR);
/* -------------------------------------------------------------------- */
@@ -206,7 +207,7 @@ PyDoc_STRVAR(GPU_export_shader_doc,
" :return: Dictionary defining the shader, uniforms and attributes.\n"
" :rtype: Dict"
);
-static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
PyObject *pyscene;
PyObject *pymat;
@@ -223,11 +224,14 @@ static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObj
GPUInputUniform *uniform;
GPUInputAttribute *attribute;
- static const char *kwlist[] = {"scene", "material", NULL};
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:export_shader", (char **)(kwlist), &pyscene, &pymat))
+ static const char *_keywords[] = {"scene", "material", NULL};
+ static _PyArg_Parser _parser = {"OO:export_shader", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &pyscene, &pymat))
+ {
return NULL;
-
+ }
scene = (Scene *)PyC_RNA_AsPointer(pyscene, "Scene");
if (scene == NULL) {
return NULL;
diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c
index c4863b2a92f..3c340d14e3f 100644
--- a/source/blender/python/intern/gpu_offscreen.c
+++ b/source/blender/python/intern/gpu_offscreen.c
@@ -144,36 +144,6 @@ static PyObject *pygpu_offscreen_unbind(BPy_GPUOffScreen *self, PyObject *args,
Py_RETURN_NONE;
}
-/**
- * Use with PyArg_ParseTuple's "O&" formatting.
- */
-static int pygpu_offscreen_check_matrix(PyObject *o, void *p)
-{
- MatrixObject **pymat_p = p;
- MatrixObject *pymat = (MatrixObject *)o;
-
- if (!MatrixObject_Check(pymat)) {
- PyErr_Format(PyExc_TypeError,
- "expected a mathutils.Matrix, not a %.200s",
- Py_TYPE(o)->tp_name);
- return 0;
- }
-
- if (BaseMath_ReadCallback(pymat) == -1) {
- return 0;
- }
-
- if ((pymat->num_col != 4) ||
- (pymat->num_row != 4))
- {
- PyErr_SetString(PyExc_ValueError, "matrix must be 4x4");
- return 0;
- }
-
- *pymat_p = pymat;
- return 1;
-}
-
PyDoc_STRVAR(pygpu_offscreen_draw_view3d_doc,
"draw_view3d(scene, view3d, region, modelview_matrix, projection_matrix)\n"
"\n"
@@ -202,15 +172,15 @@ static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *a
ARegion *ar;
GPUFX *fx;
GPUFXSettings fx_settings;
- void *rv3d_mats;
+ struct RV3DMatrixStore *rv3d_mats;
BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
if (!PyArg_ParseTupleAndKeywords(
args, kwds, "OOOO&O&:draw_view3d", (char **)(kwlist),
&py_scene, &py_view3d, &py_region,
- pygpu_offscreen_check_matrix, &py_mat_projection,
- pygpu_offscreen_check_matrix, &py_mat_modelview) ||
+ Matrix_Parse4x4, &py_mat_projection,
+ Matrix_Parse4x4, &py_mat_modelview) ||
(!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) ||
!(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) ||
!(ar = PyC_RNA_AsPointer(py_region, "Region"))))
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 5c505247a97..96ae0a9e50f 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -1,4 +1,4 @@
-/*
+/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -38,18 +38,31 @@
#endif
PyDoc_STRVAR(M_Mathutils_doc,
-"This module provides access to the math classes:\n"
+"This module provides access to math operations.\n"
+"\n"
+".. note::\n"
+"\n"
+" Classes, methods and attributes that accept vectors also accept other numeric sequences,\n"
+" such as tuples, lists."
+"\n\n"
+"Submodules:\n"
+"\n"
+".. toctree::\n"
+" :maxdepth: 1\n"
+"\n"
+" mathutils.geometry.rst\n"
+" mathutils.bvhtree.rst\n"
+" mathutils.kdtree.rst\n"
+" mathutils.interpolate.rst\n"
+" mathutils.noise.rst\n"
+"\n"
+"The :mod:`mathutils` module provides the following classes:\n"
"\n"
"- :class:`Color`,\n"
"- :class:`Euler`,\n"
"- :class:`Matrix`,\n"
"- :class:`Quaternion`,\n"
"- :class:`Vector`,\n"
-"\n"
-".. note::\n"
-"\n"
-" Classes, methods and attributes that accept vectors also accept other numeric sequences,\n"
-" such as tuples, lists."
);
static int mathutils_array_parse_fast(float *array,
int size,
@@ -219,7 +232,7 @@ int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, c
error_prefix, size, array_min);
return -1;
}
-
+
*array = PyMem_Malloc(size * sizeof(float));
memcpy(*array, ((BaseMathObject *)value)->data, size * sizeof(float));
return size;
@@ -422,7 +435,7 @@ static Mathutils_Callback *mathutils_callbacks[MATHUTILS_TOT_CB] = {NULL};
unsigned char Mathutils_RegisterCallback(Mathutils_Callback *cb)
{
unsigned char i;
-
+
/* find the first free slot */
for (i = 0; mathutils_callbacks[i]; i++) {
if (mathutils_callbacks[i] == cb) /* already registered? */
@@ -541,8 +554,8 @@ char BaseMathObject_freeze_doc[] =
;
PyObject *BaseMathObject_freeze(BaseMathObject *self)
{
- if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
- PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped data");
+ if ((self->flag & BASE_MATH_FLAG_IS_WRAP) || (self->cb_user != NULL)) {
+ PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped/owned data");
return NULL;
}
@@ -625,14 +638,14 @@ PyMODINIT_FUNC PyInit_mathutils(void)
return NULL;
mod = PyModule_Create(&M_Mathutils_module_def);
-
+
/* each type has its own new() function */
PyModule_AddObject(mod, vector_Type.tp_name, (PyObject *)&vector_Type);
PyModule_AddObject(mod, matrix_Type.tp_name, (PyObject *)&matrix_Type);
PyModule_AddObject(mod, euler_Type.tp_name, (PyObject *)&euler_Type);
PyModule_AddObject(mod, quaternion_Type.tp_name, (PyObject *)&quaternion_Type);
PyModule_AddObject(mod, color_Type.tp_name, (PyObject *)&color_Type);
-
+
/* submodule */
PyModule_AddObject(mod, "geometry", (submodule = PyInit_mathutils_geometry()));
/* XXX, python doesnt do imports with this usefully yet
diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h
index 6ac75565c66..d1fb6dcdb82 100644
--- a/source/blender/python/mathutils/mathutils.h
+++ b/source/blender/python/mathutils/mathutils.h
@@ -41,9 +41,18 @@ extern char BaseMathObject_owner_doc[];
(struct_name *)((base_type ? (base_type)->tp_alloc(base_type, 0) : _PyObject_GC_New(&(root_type))));
-/* BaseMathObject.flag */
+/** BaseMathObject.flag */
enum {
+ /**
+ * Do not own the memory used in this vector,
+ * \note This is error prone if the memory may be freed while this vector is in use.
+ * Prefer using callbacks where possible, see: #Mathutils_RegisterCallback
+ */
BASE_MATH_FLAG_IS_WRAP = (1 << 0),
+ /**
+ * Prevent changes to the vector so it can be used as a set or dictionary key for example.
+ * (typical use cases for tuple).
+ */
BASE_MATH_FLAG_IS_FROZEN = (1 << 1),
};
#define BASE_MATH_FLAG_DEFAULT 0
diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c
index add8c2451ff..9997cd9c1f5 100644
--- a/source/blender/python/mathutils/mathutils_Color.c
+++ b/source/blender/python/mathutils/mathutils_Color.c
@@ -173,7 +173,7 @@ static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c
index 54adc826af7..9492b6d67f3 100644
--- a/source/blender/python/mathutils/mathutils_Euler.c
+++ b/source/blender/python/mathutils/mathutils_Euler.c
@@ -65,7 +65,7 @@ static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
case 2:
if ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1)
return NULL;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case 1:
if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1)
return NULL;
@@ -370,7 +370,7 @@ static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 4e980e4c0e6..2578b19d5ec 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -1301,7 +1301,7 @@ PyDoc_STRVAR(Matrix_to_scale_doc,
" :return: Return the scale of a matrix.\n"
" :rtype: :class:`Vector`\n"
"\n"
-" .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n"
+" .. note:: This method does not return a negative scale on any axis because it is not possible to obtain this data from the matrix alone.\n"
);
static PyObject *Matrix_to_scale(MatrixObject *self)
{
@@ -1390,11 +1390,11 @@ PyDoc_STRVAR(Matrix_invert_doc,
"\n"
" Set the matrix to its inverse.\n"
"\n"
-" :arg fallback: Set the matrix to this value when the inverse can't be calculated\n"
+" :arg fallback: Set the matrix to this value when the inverse cannot be calculated\n"
" (instead of raising a :exc:`ValueError` exception).\n"
" :type fallback: :class:`Matrix`\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Inverse_matrix>\n"
+" .. seealso:: `Inverse matrix <https://en.wikipedia.org/wiki/Inverse_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_invert(MatrixObject *self, PyObject *args)
{
@@ -1505,7 +1505,7 @@ PyDoc_STRVAR(Matrix_invert_safe_doc,
" If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n"
" If tweaked matrix is still degenerated, set to the identity matrix instead.\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Inverse_matrix>\n"
+" .. seealso:: `Inverse Matrix <https://en.wikipedia.org/wiki/Inverse_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_invert_safe(MatrixObject *self)
{
@@ -1554,9 +1554,9 @@ PyDoc_STRVAR(Matrix_adjugate_doc,
"\n"
" Set the matrix to its adjugate.\n"
"\n"
-" .. note:: When the matrix cant be adjugated a :exc:`ValueError` exception is raised.\n"
+" .. note:: When the matrix cannot be adjugated a :exc:`ValueError` exception is raised.\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Adjugate_matrix>\n"
+" .. seealso:: `Adjugate matrix <https://en.wikipedia.org/wiki/Adjugate_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_adjugate(MatrixObject *self)
{
@@ -1641,9 +1641,9 @@ static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
PyDoc_STRVAR(Matrix_decompose_doc,
".. method:: decompose()\n"
"\n"
-" Return the location, rotation and scale components of this matrix.\n"
+" Return the translation, rotation and scale components of this matrix.\n"
"\n"
-" :return: loc, rot, scale triple.\n"
+" :return: trans, rot, scale triple.\n"
" :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)"
);
static PyObject *Matrix_decompose(MatrixObject *self)
@@ -1709,10 +1709,10 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
/* TODO, different sized matrix */
if (self->num_col == 4 && self->num_row == 4) {
- blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
+ interp_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
}
else if (self->num_col == 3 && self->num_row == 3) {
- blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
+ interp_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
}
else {
PyErr_SetString(PyExc_ValueError,
@@ -1733,7 +1733,7 @@ PyDoc_STRVAR(Matrix_determinant_doc,
" :return: Return the determinant of a matrix.\n"
" :rtype: float\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Determinant>\n"
+" .. seealso:: `Determinant <https://en.wikipedia.org/wiki/Determinant>` on Wikipedia.\n"
);
static PyObject *Matrix_determinant(MatrixObject *self)
{
@@ -1755,7 +1755,7 @@ PyDoc_STRVAR(Matrix_transpose_doc,
"\n"
" Set the matrix to its transpose.\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Transpose>\n"
+" .. seealso:: `Transpose <https://en.wikipedia.org/wiki/Transpose>` on Wikipedia.\n"
);
static PyObject *Matrix_transpose(MatrixObject *self)
{
@@ -1887,10 +1887,10 @@ PyDoc_STRVAR(Matrix_identity_doc,
"\n"
" Set the matrix to the identity matrix.\n"
"\n"
-" .. note:: An object with zero location and rotation, a scale of one,\n"
+" .. note:: An object with a location and rotation of zero, and a scale of one\n"
" will have an identity matrix.\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Identity_matrix>\n"
+" .. seealso:: `Identity matrix <https://en.wikipedia.org/wiki/Identity_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_identity(MatrixObject *self)
{
@@ -2034,7 +2034,7 @@ static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
@@ -2914,6 +2914,73 @@ PyObject *Matrix_CreatePyObject_cb(PyObject *cb_user,
return (PyObject *) self;
}
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ */
+static bool Matrix_ParseCheck(MatrixObject *pymat)
+{
+ if (!MatrixObject_Check(pymat)) {
+ PyErr_Format(PyExc_TypeError,
+ "expected a mathutils.Matrix, not a %.200s",
+ Py_TYPE(pymat)->tp_name);
+ return 0;
+ }
+ /* sets error */
+ if (BaseMath_ReadCallback(pymat) == -1) {
+ return 0;
+ }
+ return 1;
+}
+
+int Matrix_ParseAny(PyObject *o, void *p)
+{
+ MatrixObject **pymat_p = p;
+ MatrixObject *pymat = (MatrixObject *)o;
+
+ if (!Matrix_ParseCheck(pymat)) {
+ return 0;
+ }
+ *pymat_p = pymat;
+ return 1;
+}
+
+int Matrix_Parse3x3(PyObject *o, void *p)
+{
+ MatrixObject **pymat_p = p;
+ MatrixObject *pymat = (MatrixObject *)o;
+
+ if (!Matrix_ParseCheck(pymat)) {
+ return 0;
+ }
+ if ((pymat->num_col != 3) ||
+ (pymat->num_row != 3))
+ {
+ PyErr_SetString(PyExc_ValueError, "matrix must be 3x3");
+ return 0;
+ }
+
+ *pymat_p = pymat;
+ return 1;
+}
+
+int Matrix_Parse4x4(PyObject *o, void *p)
+{
+ MatrixObject **pymat_p = p;
+ MatrixObject *pymat = (MatrixObject *)o;
+
+ if (!Matrix_ParseCheck(pymat)) {
+ return 0;
+ }
+ if ((pymat->num_col != 4) ||
+ (pymat->num_row != 4))
+ {
+ PyErr_SetString(PyExc_ValueError, "matrix must be 4x4");
+ return 0;
+ }
+
+ *pymat_p = pymat;
+ return 1;
+}
/* ----------------------------------------------------------------------------
* special type for alternate access */
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index 542a0e349c7..9c84716d307 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -77,6 +77,11 @@ PyObject *Matrix_CreatePyObject_cb(
unsigned char cb_type, unsigned char cb_subtype
) ATTR_WARN_UNUSED_RESULT;
+/* PyArg_ParseTuple's "O&" formatting helpers. */
+int Matrix_ParseAny(PyObject *o, void *p);
+int Matrix_Parse3x3(PyObject *o, void *p);
+int Matrix_Parse4x4(PyObject *o, void *p);
+
extern unsigned char mathutils_matrix_row_cb_index; /* default */
extern unsigned char mathutils_matrix_col_cb_index;
extern unsigned char mathutils_matrix_translation_cb_index;
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 71b3cf8ddac..d283c717a46 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -552,7 +552,7 @@ static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index afc8a30a6b5..65450505e08 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -32,10 +32,17 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "../generic/py_capi_utils.h"
+
#ifndef MATH_STANDALONE
# include "BLI_dynstr.h"
#endif
+/**
+ * Higher dimensions are supported, for many common operations
+ * (dealing with vector/matrix multiply or handling as 3D locations)
+ * stack memory is used with a fixed size - defined here.
+ */
#define MAX_DIMENSIONS 4
/* Swizzle axes get packed into a single value that is used as a closure. Each
@@ -50,7 +57,8 @@ static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args);
static PyObject *Vector_to_tuple_ext(VectorObject *self, int ndigits);
static int row_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat);
-/* Supports 2D, 3D, and 4D vector objects both int and float values
+/**
+ * Supports 2D, 3D, and 4D vector objects both int and float values
* accepted. Mixed float and int values accepted. Ints are parsed to float
*/
static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
@@ -403,7 +411,7 @@ static PyObject *Vector_resize(VectorObject *self, PyObject *value)
return NULL;
}
- if ((size = PyLong_AsLong(value)) == -1) {
+ if ((size = PyC_Long_AsI32(value)) == -1) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize(size): "
"expected size argument to be an integer");
@@ -836,9 +844,11 @@ static PyObject *Vector_orthogonal(VectorObject *self)
}
-/*
- * Vector.reflect(mirror): return a reflected vector on the mirror normal
- * vec - ((2 * DotVecs(vec, mirror)) * mirror)
+/**
+ * Vector.reflect(mirror): return a reflected vector on the mirror normal.
+ * <pre>
+ * vec - ((2 * dot(vec, mirror)) * mirror)
+ * </pre>
*/
PyDoc_STRVAR(Vector_reflect_doc,
".. method:: reflect(mirror)\n"
@@ -1644,13 +1654,16 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
* multiplication */
-/* COLUMN VECTOR Multiplication (Matrix X Vector)
+/**
+ * column vector multiplication (Matrix * Vector)
+ * <pre>
* [1][4][7] [a]
* [2][5][8] * [b]
* [3][6][9] [c]
+ * </pre>
*
- * note: vector/matrix multiplication IS NOT COMMUTATIVE!!!!
- * note: assume read callbacks have been done first.
+ * \note Vector/Matrix multiplication is not commutative.
+ * \note Assume read callbacks have been done first.
*/
int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat)
{
@@ -2199,9 +2212,67 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos
return PyFloat_FromDouble(dot_vn_vn(self->vec, self->vec, self->size));
}
-/* Get a new Vector according to the provided swizzle. This function has little
- * error checking, as we are in control of the inputs: the closure is set by us
- * in Vector_createSwizzleGetSeter. */
+
+/**
+ * Python script used to make swizzle array:
+ *
+ * \code{.py}
+ * SWIZZLE_BITS_PER_AXIS = 3
+ * SWIZZLE_VALID_AXIS = 0x4
+ *
+ * axis_dict = {}
+ * axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3}
+ * axises = 'xyzw'
+ * while len(axises) >= 2:
+ * for axis_0 in axises:
+ * axis_0_pos = axis_pos[axis_0]
+ * for axis_1 in axises:
+ * axis_1_pos = axis_pos[axis_1]
+ * axis_dict[axis_0 + axis_1] = (
+ * '((%s | SWIZZLE_VALID_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' %
+ * (axis_0_pos, axis_1_pos))
+ * if len(axises) > 2:
+ * for axis_2 in axises:
+ * axis_2_pos = axis_pos[axis_2]
+ * axis_dict[axis_0 + axis_1 + axis_2] = (
+ * '((%s | SWIZZLE_VALID_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' %
+ * (axis_0_pos, axis_1_pos, axis_2_pos))
+ * if len(axises) > 3:
+ * for axis_3 in axises:
+ * axis_3_pos = axis_pos[axis_3]
+ * axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = (
+ * '((%s | SWIZZLE_VALID_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) ' %
+ * (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos))
+ *
+ * axises = axises[:-1]
+ *
+ *
+ * items = list(axis_dict.items())
+ * items.sort(key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3'))
+ *
+ * unique = set()
+ * for key, val in items:
+ * num = eval(val)
+ * set_str = 'Vector_swizzle_set' if (len(set(key)) == len(key)) else 'NULL'
+ * key_args = ', '.join(["'%s'" % c for c in key.upper()])
+ * print('\t{(char *)"%s", %s(getter)Vector_swizzle_get, (setter)%s, NULL, SWIZZLE%d(%s)},' %
+ * (key, (' ' * (4 - len(key))), set_str, len(key), key_args))
+ * unique.add(num)
+ *
+ * if len(unique) != len(items):
+ * print("ERROR, duplicate values found")
+ * \endcode
+ */
+
+/**
+ * Get a new Vector according to the provided swizzle bits.
+ */
static PyObject *Vector_swizzle_get(VectorObject *self, void *closure)
{
size_t axis_to;
@@ -2232,7 +2303,8 @@ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure)
return Vector_CreatePyObject(vec, axis_to, Py_TYPE(self));
}
-/* Set the items of this vector using a swizzle.
+/**
+ * Set the items of this vector using a swizzle.
* - If value is a vector or list this operates like an array copy, except that
* the destination is effectively re-ordered as defined by the swizzle. At
* most min(len(source), len(dest)) values will be copied.
@@ -2240,8 +2312,8 @@ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure)
* - If an axis appears more than once in the swizzle, the final occurrence is
* the one that determines its value.
*
- * Returns 0 on success and -1 on failure. On failure, the vector will be
- * unchanged. */
+ * \return 0 on success and -1 on failure. On failure, the vector will be unchanged.
+ */
static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure)
{
size_t size_from;
@@ -2324,19 +2396,14 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure
return 0;
}
-/* XYZW -> 0123 */
-#define AXIS_FROM_CHAR(a) (((a) != 'W') ? ((a) - 'X') : 3)
-
-#define _VA_SWIZZLE_1(a) ( \
- ((AXIS_FROM_CHAR(a) | SWIZZLE_VALID_AXIS)))
-#define _VA_SWIZZLE_2(a, b) (_VA_SWIZZLE_1(a) | \
- ((AXIS_FROM_CHAR(b) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS)))
-#define _VA_SWIZZLE_3(a, b, c) (_VA_SWIZZLE_2(a, b) | \
- ((AXIS_FROM_CHAR(c) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))
-#define _VA_SWIZZLE_4(a, b, c, d) (_VA_SWIZZLE_3(a, b, c) | \
- ((AXIS_FROM_CHAR(d) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3)))
+#define _SWIZZLE1(a) ((a) | SWIZZLE_VALID_AXIS)
+#define _SWIZZLE2(a, b) (_SWIZZLE1(a) | (((b) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS)))
+#define _SWIZZLE3(a, b, c) (_SWIZZLE2(a, b) | (((c) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))
+#define _SWIZZLE4(a, b, c, d) (_SWIZZLE3(a, b, c) | (((d) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3)))
-#define SWIZZLE(...) SET_INT_IN_POINTER(VA_NARGS_CALL_OVERLOAD(_VA_SWIZZLE_, __VA_ARGS__))
+#define SWIZZLE2(a, b) SET_INT_IN_POINTER(_SWIZZLE2(a, b))
+#define SWIZZLE3(a, b, c) SET_INT_IN_POINTER(_SWIZZLE3(a, b, c))
+#define SWIZZLE4(a, b, c, d) SET_INT_IN_POINTER(_SWIZZLE4(a, b, c, d))
/*****************************************************************************/
/* Python attributes get/set structure: */
@@ -2353,416 +2420,366 @@ static PyGetSetDef Vector_getseters[] = {
{(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL},
{(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
- /* autogenerated swizzle attrs, see python script below */
- {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X')},
- {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X')},
- {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'X')},
- {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Y')},
- {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Z')},
- {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'W')},
- {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y')},
- {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'X')},
- {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Y')},
- {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Z')},
- {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'W')},
- {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z')},
- {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'X')},
- {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Y')},
- {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Z')},
- {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'W')},
- {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W')},
- {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'X')},
- {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Y')},
- {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Z')},
- {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'W')},
- {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y')},
- {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X')},
- {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'X')},
- {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Y')},
- {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Z')},
- {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'W')},
- {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y')},
- {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'X')},
- {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Y')},
- {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Z')},
- {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'W')},
- {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z')},
- {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'X')},
- {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Y')},
- {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Z')},
- {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z', 'W')},
- {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W')},
- {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'X')},
- {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'Y')},
- {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W', 'Z')},
- {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'W')},
- {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z')},
- {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X')},
- {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'X')},
- {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Y')},
- {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Z')},
- {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'W')},
- {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y')},
- {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'X')},
- {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Y')},
- {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Z')},
- {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y', 'W')},
- {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z')},
- {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'X')},
- {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Y')},
- {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Z')},
- {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'W')},
- {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W')},
- {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'X')},
- {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W', 'Y')},
- {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'Z')},
- {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'W')},
- {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W')},
- {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X')},
- {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'X')},
- {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Y')},
- {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Z')},
- {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'W')},
- {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y')},
- {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'X')},
- {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'Y')},
- {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y', 'Z')},
- {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'W')},
- {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z')},
- {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'X')},
- {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z', 'Y')},
- {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'Z')},
- {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'W')},
- {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W')},
- {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'X')},
- {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Y')},
- {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Z')},
- {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'W')},
- {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X')},
- {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X')},
- {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'X')},
- {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Y')},
- {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Z')},
- {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'W')},
- {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y')},
- {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'X')},
- {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Y')},
- {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Z')},
- {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'W')},
- {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z')},
- {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'X')},
- {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Y')},
- {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Z')},
- {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z', 'W')},
- {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W')},
- {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'X')},
- {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'Y')},
- {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W', 'Z')},
- {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'W')},
- {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y')},
- {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X')},
- {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'X')},
- {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Y')},
- {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Z')},
- {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'W')},
- {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y')},
- {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'X')},
- {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Y')},
- {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Z')},
- {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'W')},
- {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z')},
- {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'X')},
- {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Y')},
- {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Z')},
- {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'W')},
- {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W')},
- {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'X')},
- {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Y')},
- {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Z')},
- {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'W')},
- {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z')},
- {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X')},
- {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'X')},
- {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Y')},
- {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Z')},
- {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X', 'W')},
- {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y')},
- {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'X')},
- {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Y')},
- {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Z')},
- {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'W')},
- {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z')},
- {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'X')},
- {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Y')},
- {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Z')},
- {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'W')},
- {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W')},
- {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W', 'X')},
- {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Y')},
- {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Z')},
- {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'W')},
- {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W')},
- {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X')},
- {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'X')},
- {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'Y')},
- {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X', 'Z')},
- {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'W')},
- {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y')},
- {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'X')},
- {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Y')},
- {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Z')},
- {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'W')},
- {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z')},
- {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z', 'X')},
- {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Y')},
- {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Z')},
- {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'W')},
- {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W')},
- {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'X')},
- {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Y')},
- {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Z')},
- {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'W')},
- {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X')},
- {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X')},
- {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'X')},
- {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Y')},
- {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Z')},
- {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'W')},
- {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y')},
- {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'X')},
- {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Y')},
- {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Z')},
- {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y', 'W')},
- {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z')},
- {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'X')},
- {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Y')},
- {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Z')},
- {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'W')},
- {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W')},
- {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'X')},
- {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W', 'Y')},
- {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'Z')},
- {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'W')},
- {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y')},
- {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X')},
- {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'X')},
- {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Y')},
- {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Z')},
- {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X', 'W')},
- {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y')},
- {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'X')},
- {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Y')},
- {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Z')},
- {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'W')},
- {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z')},
- {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'X')},
- {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Y')},
- {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Z')},
- {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'W')},
- {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W')},
- {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W', 'X')},
- {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Y')},
- {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Z')},
- {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'W')},
- {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z')},
- {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X')},
- {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'X')},
- {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Y')},
- {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Z')},
- {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'W')},
- {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y')},
- {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'X')},
- {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Y')},
- {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Z')},
- {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'W')},
- {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z')},
- {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'X')},
- {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Y')},
- {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Z')},
- {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'W')},
- {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W')},
- {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'X')},
- {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Y')},
- {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Z')},
- {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'W')},
- {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W')},
- {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X')},
- {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'X')},
- {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X', 'Y')},
- {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'Z')},
- {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'W')},
- {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y')},
- {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y', 'X')},
- {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Y')},
- {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Z')},
- {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'W')},
- {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z')},
- {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'X')},
- {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Y')},
- {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Z')},
- {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'W')},
- {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W')},
- {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'X')},
- {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Y')},
- {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Z')},
- {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'W')},
- {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X')},
- {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X')},
- {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'X')},
- {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Y')},
- {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Z')},
- {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'W')},
- {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y')},
- {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'X')},
- {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'Y')},
- {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y', 'Z')},
- {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'W')},
- {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z')},
- {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'X')},
- {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z', 'Y')},
- {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'Z')},
- {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'W')},
- {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W')},
- {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'X')},
- {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Y')},
- {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Z')},
- {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'W')},
- {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y')},
- {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X')},
- {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'X')},
- {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'Y')},
- {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X', 'Z')},
- {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'W')},
- {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y')},
- {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'X')},
- {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Y')},
- {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Z')},
- {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'W')},
- {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z')},
- {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z', 'X')},
- {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Y')},
- {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Z')},
- {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'W')},
- {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W')},
- {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'X')},
- {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Y')},
- {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Z')},
- {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'W')},
- {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z')},
- {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X')},
- {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'X')},
- {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X', 'Y')},
- {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'Z')},
- {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'W')},
- {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y')},
- {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y', 'X')},
- {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Y')},
- {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Z')},
- {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'W')},
- {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z')},
- {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'X')},
- {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Y')},
- {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Z')},
- {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'W')},
- {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W')},
- {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'X')},
- {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Y')},
- {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Z')},
- {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'W')},
- {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W')},
- {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X')},
- {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'X')},
- {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Y')},
- {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Z')},
- {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'W')},
- {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y')},
- {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'X')},
- {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Y')},
- {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Z')},
- {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'W')},
- {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z')},
- {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'X')},
- {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Y')},
- {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Z')},
- {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'W')},
- {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W')},
- {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'X')},
- {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Y')},
- {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Z')},
- {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'W')},
+ /* autogenerated swizzle attrs, see Python script above */
+ {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(0, 0)},
+ {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 0)},
+ {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 0)},
+ {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 1)},
+ {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 2)},
+ {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 3)},
+ {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 1)},
+ {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 0)},
+ {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 1)},
+ {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 2)},
+ {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 3)},
+ {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 2)},
+ {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 0)},
+ {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 1)},
+ {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 2)},
+ {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 3)},
+ {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 3)},
+ {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 0)},
+ {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 1)},
+ {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 2)},
+ {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 3)},
+ {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 1)},
+ {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 1, 0)},
+ {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 0)},
+ {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 1)},
+ {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 2)},
+ {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 3)},
+ {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 1, 1)},
+ {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 0)},
+ {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 1)},
+ {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 2)},
+ {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 3)},
+ {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 1, 2)},
+ {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 0)},
+ {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 1)},
+ {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 2)},
+ {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 1, 2, 3)},
+ {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 1, 3)},
+ {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 0)},
+ {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 1)},
+ {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 1, 3, 2)},
+ {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 3)},
+ {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 2)},
+ {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 2, 0)},
+ {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 0)},
+ {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 1)},
+ {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 2)},
+ {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 3)},
+ {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 2, 1)},
+ {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 0)},
+ {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 1)},
+ {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 2)},
+ {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 2, 1, 3)},
+ {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 2, 2)},
+ {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 0)},
+ {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 1)},
+ {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 2)},
+ {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 3)},
+ {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 2, 3)},
+ {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 0)},
+ {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 2, 3, 1)},
+ {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 2)},
+ {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 3)},
+ {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 3)},
+ {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 3, 0)},
+ {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 0)},
+ {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 1)},
+ {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 2)},
+ {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 3)},
+ {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 3, 1)},
+ {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 0)},
+ {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 1)},
+ {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 3, 1, 2)},
+ {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 3)},
+ {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 3, 2)},
+ {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 0)},
+ {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 3, 2, 1)},
+ {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 2)},
+ {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 3)},
+ {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 3, 3)},
+ {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 0)},
+ {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 1)},
+ {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 2)},
+ {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 3)},
+ {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 0)},
+ {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 0, 0)},
+ {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 0)},
+ {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 1)},
+ {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 2)},
+ {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 3)},
+ {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 0, 1)},
+ {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 0)},
+ {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 1)},
+ {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 2)},
+ {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 3)},
+ {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 0, 2)},
+ {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 0)},
+ {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 1)},
+ {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 2)},
+ {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 0, 2, 3)},
+ {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 0, 3)},
+ {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 0)},
+ {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 1)},
+ {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 0, 3, 2)},
+ {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 3)},
+ {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(1, 1)},
+ {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 0)},
+ {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 0)},
+ {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 1)},
+ {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 2)},
+ {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 3)},
+ {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 1)},
+ {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 0)},
+ {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 1)},
+ {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 2)},
+ {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 3)},
+ {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 2)},
+ {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 0)},
+ {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 1)},
+ {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 2)},
+ {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 3)},
+ {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 3)},
+ {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 0)},
+ {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 1)},
+ {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 2)},
+ {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 3)},
+ {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 2)},
+ {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 2, 0)},
+ {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 0)},
+ {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 1)},
+ {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 2)},
+ {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 2, 0, 3)},
+ {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 2, 1)},
+ {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 0)},
+ {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 1)},
+ {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 2)},
+ {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 3)},
+ {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 2, 2)},
+ {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 0)},
+ {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 1)},
+ {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 2)},
+ {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 3)},
+ {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 2, 3)},
+ {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 2, 3, 0)},
+ {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 1)},
+ {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 2)},
+ {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 3)},
+ {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 3)},
+ {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 3, 0)},
+ {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 0)},
+ {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 1)},
+ {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 3, 0, 2)},
+ {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 3)},
+ {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 3, 1)},
+ {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 0)},
+ {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 1)},
+ {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 2)},
+ {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 3)},
+ {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 3, 2)},
+ {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 3, 2, 0)},
+ {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 1)},
+ {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 2)},
+ {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 3)},
+ {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 3, 3)},
+ {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 0)},
+ {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 1)},
+ {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 2)},
+ {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 3)},
+ {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 0)},
+ {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 0, 0)},
+ {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 0)},
+ {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 1)},
+ {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 2)},
+ {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 3)},
+ {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 0, 1)},
+ {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 0)},
+ {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 1)},
+ {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 2)},
+ {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 0, 1, 3)},
+ {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 0, 2)},
+ {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 0)},
+ {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 1)},
+ {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 2)},
+ {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 3)},
+ {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 0, 3)},
+ {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 0)},
+ {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 0, 3, 1)},
+ {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 2)},
+ {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 3)},
+ {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 1)},
+ {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 1, 0)},
+ {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 0)},
+ {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 1)},
+ {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 2)},
+ {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 1, 0, 3)},
+ {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 1, 1)},
+ {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 0)},
+ {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 1)},
+ {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 2)},
+ {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 3)},
+ {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 1, 2)},
+ {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 0)},
+ {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 1)},
+ {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 2)},
+ {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 3)},
+ {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 1, 3)},
+ {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 1, 3, 0)},
+ {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 1)},
+ {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 2)},
+ {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 3)},
+ {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(2, 2)},
+ {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 0)},
+ {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 0)},
+ {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 1)},
+ {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 2)},
+ {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 3)},
+ {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 1)},
+ {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 0)},
+ {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 1)},
+ {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 2)},
+ {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 3)},
+ {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 2)},
+ {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 0)},
+ {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 1)},
+ {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 2)},
+ {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 3)},
+ {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 3)},
+ {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 0)},
+ {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 1)},
+ {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 2)},
+ {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 3)},
+ {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 3)},
+ {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 3, 0)},
+ {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 0)},
+ {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 3, 0, 1)},
+ {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 2)},
+ {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 3)},
+ {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 3, 1)},
+ {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 3, 1, 0)},
+ {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 1)},
+ {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 2)},
+ {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 3)},
+ {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 3, 2)},
+ {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 0)},
+ {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 1)},
+ {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 2)},
+ {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 3)},
+ {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 3, 3)},
+ {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 0)},
+ {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 1)},
+ {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 2)},
+ {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 3)},
+ {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 0)},
+ {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 0, 0)},
+ {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 0)},
+ {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 1)},
+ {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 2)},
+ {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 3)},
+ {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 0, 1)},
+ {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 0)},
+ {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 1)},
+ {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 0, 1, 2)},
+ {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 3)},
+ {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 0, 2)},
+ {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 0)},
+ {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 0, 2, 1)},
+ {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 2)},
+ {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 3)},
+ {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 0, 3)},
+ {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 0)},
+ {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 1)},
+ {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 2)},
+ {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 3)},
+ {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 1)},
+ {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 1, 0)},
+ {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 0)},
+ {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 1)},
+ {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 1, 0, 2)},
+ {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 3)},
+ {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 1, 1)},
+ {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 0)},
+ {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 1)},
+ {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 2)},
+ {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 3)},
+ {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 1, 2)},
+ {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 1, 2, 0)},
+ {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 1)},
+ {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 2)},
+ {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 3)},
+ {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 1, 3)},
+ {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 0)},
+ {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 1)},
+ {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 2)},
+ {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 3)},
+ {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 2)},
+ {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 2, 0)},
+ {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 0)},
+ {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 2, 0, 1)},
+ {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 2)},
+ {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 3)},
+ {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 2, 1)},
+ {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 2, 1, 0)},
+ {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 1)},
+ {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 2)},
+ {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 3)},
+ {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 2, 2)},
+ {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 0)},
+ {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 1)},
+ {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 2)},
+ {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 3)},
+ {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 2, 3)},
+ {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 0)},
+ {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 1)},
+ {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 2)},
+ {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 3)},
+ {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(3, 3)},
+ {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 0)},
+ {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 0)},
+ {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 1)},
+ {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 2)},
+ {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 3)},
+ {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 1)},
+ {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 0)},
+ {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 1)},
+ {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 2)},
+ {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 3)},
+ {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 2)},
+ {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 0)},
+ {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 1)},
+ {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 2)},
+ {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 3)},
+ {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 3)},
+ {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 0)},
+ {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 1)},
+ {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 2)},
+ {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 3)},
#undef AXIS_FROM_CHAR
-#undef SWIZZLE
-#undef _VA_SWIZZLE_1
-#undef _VA_SWIZZLE_2
-#undef _VA_SWIZZLE_3
-#undef _VA_SWIZZLE_4
+#undef SWIZZLE1
+#undef SWIZZLE2
+#undef SWIZZLE3
+#undef SWIZZLE4
+#undef _SWIZZLE1
+#undef _SWIZZLE2
+#undef _SWIZZLE3
+#undef _SWIZZLE4
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
/**
- * Python script used to make swizzle array:
- *
- * \code{.py}
- * SWIZZLE_BITS_PER_AXIS = 3
- * SWIZZLE_VALID_AXIS = 0x4
- *
- * axis_dict = {}
- * axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3}
- * axises = 'xyzw'
- * while len(axises) >= 2:
- * for axis_0 in axises:
- * axis_0_pos = axis_pos[axis_0]
- * for axis_1 in axises:
- * axis_1_pos = axis_pos[axis_1]
- * axis_dict[axis_0 + axis_1] = (
- * '((%s | SWIZZLE_VALID_AXIS) | '
- * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' %
- * (axis_0_pos, axis_1_pos))
- * if len(axises) > 2:
- * for axis_2 in axises:
- * axis_2_pos = axis_pos[axis_2]
- * axis_dict[axis_0 + axis_1 + axis_2] = (
- * '((%s | SWIZZLE_VALID_AXIS) | '
- * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | '
- * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' %
- * (axis_0_pos, axis_1_pos, axis_2_pos))
- * if len(axises) > 3:
- * for axis_3 in axises:
- * axis_3_pos = axis_pos[axis_3]
- * axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = (
- * '((%s | SWIZZLE_VALID_AXIS) | '
- * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | '
- * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | '
- * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) ' %
- * (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos))
- *
- * axises = axises[:-1]
- *
- *
- * items = list(axis_dict.items())
- * items.sort(key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3'))
- *
- * unique = set()
- * for key, val in items:
- * num = eval(val)
- * set_str = 'Vector_swizzle_set' if (len(set(key)) == len(key)) else 'NULL'
- * key_args = ', '.join(["'%s'" % c for c in key.upper()])
- * print('\t{(char *)"%s", %s(getter)Vector_swizzle_get, (setter)%s, NULL, SWIZZLE(%s)},' %
- * (key, (' ' * (4 - len(key))), set_str, key_args))
- * unique.add(num)
- *
- * if len(unique) != len(items):
- * print("ERROR, duplicate values found")
- * \endcode
- */
-
-/* ROW VECTOR Multiplication - Vector X Matrix
+ * Row vector multiplication - (Vector * Matrix)
+ * <pre>
* [x][y][z] * [1][4][7]
* [2][5][8]
* [3][6][9]
- * vector/matrix multiplication IS NOT COMMUTATIVE!!!! */
+ * </pre>
+ * \note vector/matrix multiplication is not commutative.
+ */
static int row_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat)
{
float vec_cpy[MAX_DIMENSIONS];
@@ -2863,10 +2880,11 @@ static struct PyMethodDef Vector_methods[] = {
};
-/* Note
- * Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing
- * but this means for eg that
- * (vec * mat) and (mat * vec) both get sent to Vector_mul and it needs to sort out the order
+/**
+ * Note:
+ * #Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing
+ * but this means for eg that (vec * mat) and (mat * vec)
+ * both get sent to Vector_mul and it needs to sort out the order
*/
PyDoc_STRVAR(vector_doc,
@@ -3010,6 +3028,11 @@ PyObject *Vector_CreatePyObject(
return (PyObject *)self;
}
+/**
+ * Create a vector that wraps existing memory.
+ *
+ * \param vec: Use this vector in-place.
+ */
PyObject *Vector_CreatePyObject_wrap(
float *vec, const int size,
PyTypeObject *base_type)
@@ -3036,6 +3059,10 @@ PyObject *Vector_CreatePyObject_wrap(
return (PyObject *) self;
}
+/**
+ * Create a vector where the value is defined by registered callbacks,
+ * see: #Mathutils_RegisterCallback
+ */
PyObject *Vector_CreatePyObject_cb(
PyObject *cb_user, int size,
unsigned char cb_type, unsigned char cb_subtype)
@@ -3052,6 +3079,9 @@ PyObject *Vector_CreatePyObject_cb(
return (PyObject *)self;
}
+/**
+ * \param vec: Initialized vector value to use in-place, allocated with: PyMem_Malloc
+ */
PyObject *Vector_CreatePyObject_alloc(
float *vec, const int size,
PyTypeObject *base_type)
diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c
index ff1761eb6d7..42771d93b4e 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.c
+++ b/source/blender/python/mathutils/mathutils_bvhtree.c
@@ -761,7 +761,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P
py_tricoords_fast_items = PySequence_Fast_ITEMS(py_tricoords_fast);
for (j = 0; j < 3; j++) {
- tri[j] = (unsigned int)_PyLong_AsInt(py_tricoords_fast_items[j]);
+ tri[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]);
if (UNLIKELY(tri[j] >= (unsigned int)coords_len)) {
PyErr_Format(PyExc_ValueError,
"%s: index %d must be less than %d",
@@ -812,18 +812,19 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P
p_plink_prev = &plink->next;
for (j = 0; j < py_tricoords_len; j++) {
- plink->poly[j] = (unsigned int)_PyLong_AsInt(py_tricoords_fast_items[j]);
+ plink->poly[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]);
if (UNLIKELY(plink->poly[j] >= (unsigned int)coords_len)) {
PyErr_Format(PyExc_ValueError,
"%s: index %d must be less than %d",
error_prefix, plink->poly[j], coords_len);
-
- Py_DECREF(py_tricoords_fast);
+ /* decref below */
valid = false;
break;
}
}
+ Py_DECREF(py_tricoords_fast);
+
if (py_tricoords_len >= 3) {
tris_len += (py_tricoords_len - 2);
}
@@ -1155,7 +1156,6 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO
/* Get data for tessellation */
{
- DM_ensure_looptri(dm);
lt = dm->getLoopTriArray(dm);
tris_len = (unsigned int)dm->getNumLoopTri(dm);
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index 868e4b38408..1dc18dbe509 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -1279,7 +1279,7 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject
index = 0;
dl_face = dl->index;
while (index < dl->parts) {
- PyList_SET_ITEM(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2]));
+ PyList_SET_ITEM(tri_list, index, PyC_Tuple_Pack_I32(dl_face[0], dl_face[1], dl_face[2]));
dl_face += 3;
index++;
}
diff --git a/source/blender/quicktime/apple/qtkit_export.m b/source/blender/quicktime/apple/qtkit_export.m
deleted file mode 100644
index 1ac3c58f888..00000000000
--- a/source/blender/quicktime/apple/qtkit_export.m
+++ /dev/null
@@ -1,884 +0,0 @@
-/*
- * Code to create QuickTime Movies with Blender
- *
- * ***** 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 written by Rob Haarsma (phase)
- *
- * Contributor(s): Stefan Gartner (sgefant)
- * Damien Plisson 11/2009
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifdef WITH_QUICKTIME
-#if defined(_WIN32) || defined(__APPLE__)
-
-#include <stdio.h>
-#include <string.h>
-
-#include "DNA_scene_types.h"
-#include "DNA_userdef_types.h"
-
-#ifdef WITH_AUDASPACE
-# include AUD_DEVICE_H
-#endif
-
-#include "BLI_utildefines.h"
-#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_scene.h"
-#include "BKE_report.h"
-
-#include "BLI_blenlib.h"
-
-#include "BLI_sys_types.h"
-
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#ifdef __APPLE__
-/* evil */
-#ifndef __AIFF__
-#define __AIFF__
-#endif
-#import <Cocoa/Cocoa.h>
-#import <QTKit/QTKit.h>
-#include <AudioToolbox/AudioToolbox.h>
-
-#include "quicktime_import.h"
-#include "quicktime_export.h"
-
-#endif /* __APPLE__ */
-
-typedef struct QuicktimeExport {
- QTMovie *movie;
-
- NSString *filename;
-
- QTTime frameDuration;
- NSDictionary *frameAttributes;
-
- NSString *videoTempFileName;
- /* Audio section */
- AUD_Device *audioInputDevice;
- AudioFileID audioFile;
- NSString *audioFileName;
- AudioConverterRef audioConverter;
- AudioBufferList audioBufferList;
- AudioStreamBasicDescription audioInputFormat, audioOutputFormat;
- AudioStreamPacketDescription *audioOutputPktDesc;
- SInt64 audioFilePos;
- char *audioInputBuffer;
- char *audioOutputBuffer;
- UInt32 audioCodecMaxOutputPacketSize;
- UInt64 audioTotalExportedFrames, audioTotalSavedFrames;
- UInt64 audioLastFrame;
- SInt64 audioOutputPktPos;
-
-} QuicktimeExport;
-
-#define AUDIOOUTPUTBUFFERSIZE 65536
-
-#pragma mark rna helper functions
-
-/* Video codec */
-static QuicktimeCodecTypeDesc qtVideoCodecList[] = {
- {kRawCodecType, 1, "Uncompressed"},
- {k422YpCbCr8CodecType, 2, "Uncompressed 8-bit 4:2:2"},
- {k422YpCbCr10CodecType, 3, "Uncompressed 10-bit 4:2:2"},
- {kComponentVideoCodecType, 4, "Component Video"},
- {kPixletCodecType, 5, "Pixlet"},
- {kPNGCodecType, 6, "PNG"},
- {kJPEGCodecType, 7, "JPEG"},
- {kMotionJPEGACodecType, 8, "M-JPEG A"},
- {kMotionJPEGBCodecType, 9, "M-JPEG B"},
- {kDVCPALCodecType, 10, "DV PAL"},
- {kDVCNTSCCodecType, 11, "DV/DVCPRO NTSC"},
- {kDVCPROHD720pCodecType, 12, "DVCPRO HD 720p"},
- {kDVCPROHD1080i50CodecType, 13, "DVCPRO HD 1080i50"},
- {kDVCPROHD1080i60CodecType, 14, "DVCPRO HD 1080i60"},
- {kMPEG4VisualCodecType, 15, "MPEG4"},
- {kH263CodecType, 16, "H.263"},
- {kH264CodecType, 17, "H.264"},
- {kAnimationCodecType, 18, "Animation"},
- {0,0,NULL}};
-
-static int qtVideoCodecCount = 18;
-
-int quicktime_get_num_videocodecs()
-{
- return qtVideoCodecCount;
-}
-
-QuicktimeCodecTypeDesc* quicktime_get_videocodecType_desc(int indexValue)
-{
- if ((indexValue>=0) && (indexValue < qtVideoCodecCount))
- return &qtVideoCodecList[indexValue];
- else
- return NULL;
-}
-
-int quicktime_rnatmpvalue_from_videocodectype(int codecType)
-{
- int i;
- for (i = 0; i < qtVideoCodecCount; i++) {
- if (qtVideoCodecList[i].codecType == codecType)
- return qtVideoCodecList[i].rnatmpvalue;
- }
-
- return 0;
-}
-
-int quicktime_videocodecType_from_rnatmpvalue(int rnatmpvalue)
-{
- int i;
- for (i = 0; i < qtVideoCodecCount; i++) {
- if (qtVideoCodecList[i].rnatmpvalue == rnatmpvalue)
- return qtVideoCodecList[i].codecType;
- }
-
- return 0;
-}
-
-/* Audio codec */
-static QuicktimeCodecTypeDesc qtAudioCodecList[] = {
- {0, 0, "No audio"},
- {kAudioFormatLinearPCM, 1, "LPCM"},
- {kAudioFormatAppleLossless, 2, "Apple Lossless"},
- {kAudioFormatMPEG4AAC, 3, "AAC"},
- {0,0,NULL}};
-
-static int qtAudioCodecCount = 4;
-
-int quicktime_get_num_audiocodecs()
-{
- return qtAudioCodecCount;
-}
-
-QuicktimeCodecTypeDesc* quicktime_get_audiocodecType_desc(int indexValue)
-{
- if ((indexValue>=0) && (indexValue < qtAudioCodecCount))
- return &qtAudioCodecList[indexValue];
- else
- return NULL;
-}
-
-int quicktime_rnatmpvalue_from_audiocodectype(int codecType)
-{
- int i;
- for (i = 0; i < qtAudioCodecCount; i++) {
- if (qtAudioCodecList[i].codecType == codecType)
- return qtAudioCodecList[i].rnatmpvalue;
- }
-
- return 0;
-}
-
-int quicktime_audiocodecType_from_rnatmpvalue(int rnatmpvalue)
-{
- int i;
- for (i = 0; i < qtAudioCodecCount; i++) {
- if (qtAudioCodecList[i].rnatmpvalue == rnatmpvalue)
- return qtAudioCodecList[i].codecType;
- }
-
- return 0;
-}
-
-
-static NSString *stringWithCodecType(int codecType)
-{
- char str[5];
-
- *((int *)str) = EndianU32_NtoB(codecType);
- str[4] = 0;
-
- return [NSString stringWithCString:str encoding:NSASCIIStringEncoding];
-}
-
-void makeqtstring(RenderData *rd, char *string, bool preview)
-{
- int sfra, efra;
-
- char txt[64];
-
- if (preview) {
- sfra = rd->psfra;
- efra = rd->pefra;
- }
- else {
- sfra = rd->sfra;
- efra = rd->efra;
- }
-
- strcpy(string, rd->pic);
- BLI_path_abs(string, G.main->name);
-
- BLI_make_existing_file(string);
-
- if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) {
- sprintf(txt, "%04d-%04d.mov", (rd->sfra) , (rd->efra) );
- strcat(string, txt);
- }
-}
-
-void filepath_qt(char *string, RenderData *rd, bool preview, const char *suffix)
-{
- int sfra, efra;
-
- if (string == NULL) return;
-
- if (preview) {
- sfra = rd->psfra;
- efra = rd->pefra;
- }
- else {
- sfra = rd->sfra;
- efra = rd->efra;
- }
-
- strcpy(string, rd->pic);
- BLI_path_abs(string, G.main->name);
-
- BLI_make_existing_file(string);
-
- if (rd->scemode & R_EXTENSION) {
- if (!BLI_testextensie(string, ".mov")) {
- BLI_path_frame_range(string, sfra, efra, 4);
- strcat(string, ".mov");
- }
- }
- else {
- if (BLI_path_frame_check_chars(string)) {
- BLI_path_frame_range(string, sfra, efra, 4);
- }
- }
-
- BLI_path_suffix(string, FILE_MAX, suffix, "");
-}
-
-void *context_create_qt(void)
-{
- QuicktimeExport *qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
- return qtexport;
-}
-
-void context_free_qt(void *context_v)
-{
- QuicktimeExport *qtexport = context_v;
- if (qtexport) {
- MEM_freeN(qtexport);
- }
-}
-
-#pragma mark audio export functions
-
-static OSStatus write_cookie(AudioConverterRef converter, AudioFileID outfile)
-{
- // grab the cookie from the converter and write it to the file
- UInt32 cookieSize = 0;
- OSStatus err = AudioConverterGetPropertyInfo(converter, kAudioConverterCompressionMagicCookie, &cookieSize, NULL);
- // if there is an error here, then the format doesn't have a cookie, so on we go
- if (!err && cookieSize) {
- char* cookie = malloc(cookieSize);
-
- err = AudioConverterGetProperty(converter, kAudioConverterCompressionMagicCookie, &cookieSize, cookie);
-
- if (!err)
- err = AudioFileSetProperty (outfile, kAudioFilePropertyMagicCookieData, cookieSize, cookie);
- // even though some formats have cookies, some files don't take them
-
- free(cookie);
- }
- return err;
-}
-
-/* AudioConverter input stream callback */
-static OSStatus AudioConverterInputCallback(AudioConverterRef inAudioConverter,
- UInt32* ioNumberDataPackets,
- AudioBufferList* ioData,
- AudioStreamPacketDescription** outDataPacketDescription,
- void* inUserData)
-{
- QuicktimeExport *qtexport = inUserData;
- if (qtexport->audioTotalExportedFrames >= qtexport->audioLastFrame) { /* EOF */
- *ioNumberDataPackets = 0;
- return noErr;
- }
-
- if (qtexport->audioInputFormat.mBytesPerPacket * *ioNumberDataPackets > AUDIOOUTPUTBUFFERSIZE)
- *ioNumberDataPackets = AUDIOOUTPUTBUFFERSIZE / qtexport->audioInputFormat.mBytesPerPacket;
-
- if ((qtexport->audioTotalExportedFrames + *ioNumberDataPackets) > qtexport->audioLastFrame)
- *ioNumberDataPackets = (qtexport->audioLastFrame - qtexport->audioTotalExportedFrames) / qtexport->audioInputFormat.mFramesPerPacket;
-
- qtexport->audioTotalExportedFrames += *ioNumberDataPackets;
-
- AUD_Device_read(qtexport->audioInputDevice, (UInt8 *)qtexport->audioInputBuffer,
- qtexport->audioInputFormat.mFramesPerPacket * *ioNumberDataPackets);
-
- ioData->mBuffers[0].mDataByteSize = qtexport->audioInputFormat.mBytesPerPacket * *ioNumberDataPackets;
- ioData->mBuffers[0].mData = qtexport->audioInputBuffer;
- ioData->mBuffers[0].mNumberChannels = qtexport->audioInputFormat.mChannelsPerFrame;
-
- return noErr;
-}
-
-
-#pragma mark export functions
-
-int start_qt(
- void *context_v, struct Scene *scene, struct RenderData *rd, int UNUSED(rectx), int UNUSED(recty),
- ReportList *reports, bool preview, const char *UNUSED(suffix))
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSError *error;
- char name[1024];
- int success = 1;
- OSStatus err = noErr;
- int sfra, efra;
- QuicktimeExport *qtexport = context_v;
-
- if (preview) {
- sfra = rd->psfra;
- efra = rd->pefra;
- }
- else {
- sfra = rd->sfra;
- efra = rd->efra;
- }
-
- [QTMovie enterQTKitOnThread];
-
- /* Check first if the QuickTime 7.2.1 initToWritableFile: method is available */
- if ([[[[QTMovie alloc] init] autorelease] respondsToSelector:@selector(initToWritableFile:error:)] != YES) {
- BKE_report(reports, RPT_ERROR, "\nUnable to create quicktime movie, need Quicktime rev 7.2.1 or later");
- success = 0;
- }
- else {
- makeqtstring(rd, name, preview);
- qtexport->filename = [[NSString alloc] initWithUTF8String:name];
- qtexport->movie = nil;
- qtexport->audioFile = NULL;
-
- if (rd->qtcodecsettings.audiocodecType) {
- // generate a name for our video & audio files
- /* Init audio file */
- CFURLRef outputFileURL;
- char extension[32];
- AudioFileTypeID audioFileType;
-
- switch (rd->qtcodecsettings.audiocodecType) {
- case kAudioFormatLinearPCM:
- audioFileType = kAudioFileWAVEType;
- strcpy(extension,".wav");
- break;
- case kAudioFormatMPEG4AAC:
- case kAudioFormatAppleLossless:
- audioFileType = kAudioFileM4AType;
- strcpy(extension, ".m4a");
- break;
- default:
- audioFileType = kAudioFileAIFFType;
- strcpy(extension,".aiff");
- break;
- }
-
- tmpnam(name);
- strcat(name, extension);
- outputFileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,(UInt8 *)name, strlen(name), false);
-
- if (outputFileURL) {
-
- qtexport->audioFileName = [[NSString alloc] initWithCString:name
- encoding:[NSString defaultCStringEncoding]];
-
- qtexport->audioInputFormat.mSampleRate = U.audiorate;
- qtexport->audioInputFormat.mFormatID = kAudioFormatLinearPCM;
- qtexport->audioInputFormat.mChannelsPerFrame = U.audiochannels;
- switch (U.audioformat) {
- case AUD_FORMAT_U8:
- qtexport->audioInputFormat.mBitsPerChannel = 8;
- qtexport->audioInputFormat.mFormatFlags = 0;
- break;
- case AUD_FORMAT_S24:
- qtexport->audioInputFormat.mBitsPerChannel = 24;
- qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
- break;
- case AUD_FORMAT_S32:
- qtexport->audioInputFormat.mBitsPerChannel = 32;
- qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
- break;
- case AUD_FORMAT_FLOAT32:
- qtexport->audioInputFormat.mBitsPerChannel = 32;
- qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
- break;
- case AUD_FORMAT_FLOAT64:
- qtexport->audioInputFormat.mBitsPerChannel = 64;
- qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
- break;
- case AUD_FORMAT_S16:
- default:
- qtexport->audioInputFormat.mBitsPerChannel = 16;
- qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
- break;
- }
- qtexport->audioInputFormat.mBytesPerFrame = qtexport->audioInputFormat.mChannelsPerFrame * qtexport->audioInputFormat.mBitsPerChannel / 8;
- qtexport->audioInputFormat.mFramesPerPacket = 1; /*If not ==1, then need to check input callback for "rounding" issues"*/
- qtexport->audioInputFormat.mBytesPerPacket = qtexport->audioInputFormat.mBytesPerFrame;
- qtexport->audioInputFormat.mFormatFlags |= kLinearPCMFormatFlagIsPacked;
-
-
- /*Output format*/
- qtexport->audioOutputFormat.mFormatID = rd->qtcodecsettings.audiocodecType;
- //TODO: set audio channels
- qtexport->audioOutputFormat.mChannelsPerFrame = 2;
- qtexport->audioOutputFormat.mSampleRate = rd->qtcodecsettings.audioSampleRate;
-
- /* Default value for compressed formats, overridden after if not the case */
- qtexport->audioOutputFormat.mFramesPerPacket = 0;
- qtexport->audioOutputFormat.mBytesPerFrame = 0;
- qtexport->audioOutputFormat.mBytesPerPacket = 0;
- qtexport->audioOutputFormat.mBitsPerChannel = 0;
-
- switch (rd->qtcodecsettings.audiocodecType) {
- case kAudioFormatMPEG4AAC:
- qtexport->audioOutputFormat.mFormatFlags = kMPEG4Object_AAC_Main;
- /* AAC codec does not handle sample rates above 48kHz, force this limit instead of getting an error afterwards */
- if (qtexport->audioOutputFormat.mSampleRate > 48000) qtexport->audioOutputFormat.mSampleRate = 48000;
- break;
- case kAudioFormatAppleLossless:
- switch (U.audioformat) {
- case AUD_FORMAT_S16:
- qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_16BitSourceData;
- break;
- case AUD_FORMAT_S24:
- qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_24BitSourceData;
- break;
- case AUD_FORMAT_S32:
- qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_32BitSourceData;
- break;
- case AUD_FORMAT_U8:
- case AUD_FORMAT_FLOAT32:
- case AUD_FORMAT_FLOAT64:
- default:
- break;
- }
- break;
- case kAudioFormatLinearPCM:
- default:
- switch (rd->qtcodecsettings.audioBitDepth) {
- case AUD_FORMAT_U8:
- qtexport->audioOutputFormat.mBitsPerChannel = 8;
- qtexport->audioOutputFormat.mFormatFlags = 0;
- break;
- case AUD_FORMAT_S24:
- qtexport->audioOutputFormat.mBitsPerChannel = 24;
- qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
- break;
- case AUD_FORMAT_S32:
- qtexport->audioOutputFormat.mBitsPerChannel = 32;
- qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
- break;
- case AUD_FORMAT_FLOAT32:
- qtexport->audioOutputFormat.mBitsPerChannel = 32;
- qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
- break;
- case AUD_FORMAT_FLOAT64:
- qtexport->audioOutputFormat.mBitsPerChannel = 64;
- qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
- break;
- case AUD_FORMAT_S16:
- default:
- qtexport->audioOutputFormat.mBitsPerChannel = 16;
- qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
- break;
- }
- qtexport->audioOutputFormat.mFormatFlags |= kLinearPCMFormatFlagIsPacked;
- qtexport->audioOutputFormat.mBytesPerPacket = qtexport->audioOutputFormat.mChannelsPerFrame * (qtexport->audioOutputFormat.mBitsPerChannel / 8);
- qtexport->audioOutputFormat.mFramesPerPacket = 1;
- qtexport->audioOutputFormat.mBytesPerFrame = qtexport->audioOutputFormat.mBytesPerPacket;
- break;
- }
-
- err = AudioFileCreateWithURL(outputFileURL, audioFileType, &qtexport->audioOutputFormat, kAudioFileFlags_EraseFile, &qtexport->audioFile);
- CFRelease(outputFileURL);
-
- if (err)
- BKE_report(reports, RPT_ERROR, "\nQuicktime: unable to create temporary audio file. Format error ?");
- else {
- err = AudioConverterNew(&qtexport->audioInputFormat, &qtexport->audioOutputFormat, &qtexport->audioConverter);
- if (err) {
- BKE_report(reports, RPT_ERROR, "\nQuicktime: unable to initialize audio codec converter. Format error ?");
- AudioFileClose(qtexport->audioFile);
- qtexport->audioFile = NULL;
- [qtexport->audioFileName release];
- qtexport->audioFileName = nil;
- }
- else {
- UInt32 prop,propSize;
- /* Set up codec properties */
- if (rd->qtcodecsettings.audiocodecType == kAudioFormatMPEG4AAC) { /* Lossy compressed format */
- prop = rd->qtcodecsettings.audioBitRate;
- AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterEncodeBitRate,
- sizeof(prop), &prop);
-
- if (rd->qtcodecsettings.audioCodecFlags & QTAUDIO_FLAG_CODEC_ISCBR)
- prop = kAudioCodecBitRateControlMode_Constant;
- else
- prop = kAudioCodecBitRateControlMode_LongTermAverage;
- AudioConverterSetProperty(qtexport->audioConverter, kAudioCodecPropertyBitRateControlMode,
- sizeof(prop), &prop);
- }
- /* Conversion quality : if performance impact then offer degraded option */
- if ((rd->qtcodecsettings.audioCodecFlags & QTAUDIO_FLAG_RESAMPLE_NOHQ) == 0) {
- prop = kAudioConverterSampleRateConverterComplexity_Mastering;
- AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterSampleRateConverterComplexity,
- sizeof(prop), &prop);
-
- prop = kAudioConverterQuality_Max;
- AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterSampleRateConverterQuality,
- sizeof(prop), &prop);
- }
-
- write_cookie(qtexport->audioConverter, qtexport->audioFile);
-
- /* Allocate output buffer */
- if (qtexport->audioOutputFormat.mBytesPerPacket ==0) /* VBR */
- AudioConverterGetProperty(qtexport->audioConverter, kAudioConverterPropertyMaximumOutputPacketSize,
- &propSize, &qtexport->audioCodecMaxOutputPacketSize);
- else
- qtexport->audioCodecMaxOutputPacketSize = qtexport->audioOutputFormat.mBytesPerPacket;
-
- qtexport->audioInputBuffer = MEM_mallocN(AUDIOOUTPUTBUFFERSIZE, "qt_audio_inputPacket");
- qtexport->audioOutputBuffer = MEM_mallocN(AUDIOOUTPUTBUFFERSIZE, "qt_audio_outputPacket");
- qtexport->audioOutputPktDesc = MEM_mallocN(sizeof(AudioStreamPacketDescription) * AUDIOOUTPUTBUFFERSIZE / qtexport->audioCodecMaxOutputPacketSize,
- "qt_audio_pktdesc");
- }
- }
- }
-
- if (err == noErr) {
- qtexport->videoTempFileName = [[NSString alloc] initWithCString:tmpnam(nil)
- encoding:[NSString defaultCStringEncoding]];
- if (qtexport->videoTempFileName) {
- qtexport->movie = [[QTMovie alloc] initToWritableFile:qtexport->videoTempFileName error:&error];
- }
-
- }
- }
- else
- qtexport->movie = [[QTMovie alloc] initToWritableFile:qtexport->filename error:&error];
-
- if (qtexport->movie == nil) {
- BKE_report(reports, RPT_ERROR, "Unable to create quicktime movie.");
- success = 0;
- if (qtexport->filename) [qtexport->filename release];
- qtexport->filename = nil;
- if (qtexport->audioFileName) [qtexport->audioFileName release];
- qtexport->audioFileName = nil;
- if (qtexport->videoTempFileName) [qtexport->videoTempFileName release];
- qtexport->videoTempFileName = nil;
- [QTMovie exitQTKitOnThread];
- }
- else {
- [qtexport->movie retain];
- [qtexport->movie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute];
- [qtexport->movie setAttribute:@"Made with Blender" forKey:QTMovieCopyrightAttribute];
-
- qtexport->frameDuration = QTMakeTime(rd->frs_sec_base * 1000, rd->frs_sec * 1000);
-
- /* specifying the codec attributes : try to retrieve them from render data first*/
- if (rd->qtcodecsettings.codecType) {
- qtexport->frameAttributes = [
- NSDictionary dictionaryWithObjectsAndKeys:
- stringWithCodecType(rd->qtcodecsettings.codecType),
- QTAddImageCodecType,
- [NSNumber numberWithLong:((rd->qtcodecsettings.codecSpatialQuality)*codecLosslessQuality)/100],
- QTAddImageCodecQuality,
- nil];
- }
- else {
- qtexport->frameAttributes = [
- NSDictionary dictionaryWithObjectsAndKeys:@"jpeg",
- QTAddImageCodecType,
- [NSNumber numberWithLong:codecHighQuality],
- QTAddImageCodecQuality,
- nil];
- }
- [qtexport->frameAttributes retain];
-
- if (qtexport->audioFile) {
- /* Init audio input stream */
- AUD_DeviceSpecs specs;
-
- specs.channels = U.audiochannels;
- specs.format = U.audioformat;
- specs.rate = U.audiorate;
- qtexport->audioInputDevice = AUD_openReadDevice(specs);
- AUD_playDevice(qtexport->audioInputDevice, scene->sound_scene, sfra * rd->frs_sec_base / rd->frs_sec);
-
- qtexport->audioOutputPktPos = 0;
- qtexport->audioTotalExportedFrames = 0;
- qtexport->audioTotalSavedFrames = 0;
-
- qtexport->audioLastFrame = (efra - sfra) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec;
- }
- }
- }
-
- [pool drain];
-
- return success;
-}
-
-int append_qt(
- void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty,
- const char *UNUSED(suffix), ReportList *reports)
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSBitmapImageRep *blBitmapFormatImage;
- NSImage *frameImage;
- OSStatus err = noErr;
- unsigned char *from_Ptr,*to_Ptr;
- int y,from_i,to_i;
- QuicktimeExport *qtexport = context_v;
-
- /* Create bitmap image rep in blender format (32bit RGBA) */
- blBitmapFormatImage = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
- pixelsWide:rectx
- pixelsHigh:recty
- bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO
- colorSpaceName:NSCalibratedRGBColorSpace
- bitmapFormat:NSAlphaNonpremultipliedBitmapFormat
- bytesPerRow:rectx*4
- bitsPerPixel:32];
- if (!blBitmapFormatImage) {
- [pool drain];
- return 0;
- }
-
- from_Ptr = (unsigned char *)pixels;
- to_Ptr = (unsigned char *)[blBitmapFormatImage bitmapData];
- for (y = 0; y < recty; y++) {
- to_i = (recty-y-1)*rectx;
- from_i = y*rectx;
- memcpy(to_Ptr+4*to_i, from_Ptr+4*from_i, 4*rectx);
- }
-
- frameImage = [[NSImage alloc] initWithSize:NSMakeSize(rectx, recty)];
- [frameImage addRepresentation:blBitmapFormatImage];
-
- /* Add the image to the movie clip */
- [qtexport->movie addImage:frameImage
- forDuration:qtexport->frameDuration
- withAttributes:qtexport->frameAttributes];
-
- [blBitmapFormatImage release];
- [frameImage release];
-
-
- if (qtexport->audioFile) {
- UInt32 audioPacketsConverted;
-
- // Upper limit on total exported audio frames for this particular video frame
- const UInt64 exportedAudioFrameLimit = (frame - start_frame) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec;
-
- /* Append audio */
- while (qtexport->audioTotalExportedFrames < exportedAudioFrameLimit) {
-
- qtexport->audioBufferList.mNumberBuffers = 1;
- qtexport->audioBufferList.mBuffers[0].mNumberChannels = qtexport->audioOutputFormat.mChannelsPerFrame;
- qtexport->audioBufferList.mBuffers[0].mDataByteSize = AUDIOOUTPUTBUFFERSIZE;
- qtexport->audioBufferList.mBuffers[0].mData = qtexport->audioOutputBuffer;
-
- // Convert one audio packet at a time so that enclosing while loop can
- // keep audio processing in sync with video frames.
- // Previously, this was set to (AUDIOOUTPUTBUFFERSIZE / qtexport->audioCodecMaxOutputPacketSize),
- // however this may cause AudioConverterFillComplexBuffer to convert audio spanning multiple
- // video frames, which breaks animation of audio parameters such as volume for fade-in/out.
- audioPacketsConverted = 1;
-
- err = AudioConverterFillComplexBuffer(qtexport->audioConverter, AudioConverterInputCallback,
- qtexport, &audioPacketsConverted, &qtexport->audioBufferList, qtexport->audioOutputPktDesc);
- if (audioPacketsConverted) {
- AudioFileWritePackets(qtexport->audioFile, false, qtexport->audioBufferList.mBuffers[0].mDataByteSize,
- qtexport->audioOutputPktDesc, qtexport->audioOutputPktPos, &audioPacketsConverted, qtexport->audioOutputBuffer);
- qtexport->audioOutputPktPos += audioPacketsConverted;
-
- if (qtexport->audioOutputFormat.mFramesPerPacket) {
- // this is the common case: format has constant frames per packet
- qtexport->audioTotalSavedFrames += (audioPacketsConverted * qtexport->audioOutputFormat.mFramesPerPacket);
- }
- else {
- unsigned int i;
- // if there are variable frames per packet, then we have to do this for each packeet
- for (i = 0; i < audioPacketsConverted; ++i)
- qtexport->audioTotalSavedFrames += qtexport->audioOutputPktDesc[i].mVariableFramesInPacket;
- }
-
-
- }
- else {
- //Error getting audio packets
- BKE_reportf(reports, RPT_ERROR, "Unable to get further audio packets from frame %i, error = 0x%x",(int)qtexport->audioTotalExportedFrames,err);
- break;
- }
-
- }
- }
- [pool drain];
-
- return 1;
-}
-
-
-void end_qt(void *context_v)
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- QuicktimeExport *qtexport = context_v;
-
- if (qtexport->movie) {
-
- if (qtexport->audioFile)
- {
- NSDictionary *dict = nil;
- QTMovie *audioTmpMovie = nil;
- NSError *error;
- NSFileManager *fileManager;
-
- /* Mux video and audio then save file */
-
- /* Write last frames for VBR files */
- if (qtexport->audioOutputFormat.mBitsPerChannel == 0) {
- OSStatus err = noErr;
- AudioConverterPrimeInfo primeInfo;
- UInt32 primeSize = sizeof(primeInfo);
-
- err = AudioConverterGetProperty(qtexport->audioConverter, kAudioConverterPrimeInfo, &primeSize, &primeInfo);
- if (err == noErr) {
- // there's priming to write out to the file
- AudioFilePacketTableInfo pti;
- pti.mPrimingFrames = primeInfo.leadingFrames;
- pti.mRemainderFrames = primeInfo.trailingFrames;
- pti.mNumberValidFrames = qtexport->audioTotalSavedFrames - pti.mPrimingFrames - pti.mRemainderFrames;
- AudioFileSetProperty(qtexport->audioFile, kAudioFilePropertyPacketTableInfo, sizeof(pti), &pti);
- }
-
- }
-
- write_cookie(qtexport->audioConverter, qtexport->audioFile);
- AudioConverterDispose(qtexport->audioConverter);
- AudioFileClose(qtexport->audioFile);
- AUD_Device_free(qtexport->audioInputDevice);
- qtexport->audioFile = NULL;
- qtexport->audioInputDevice = NULL;
- MEM_freeN(qtexport->audioInputBuffer);
- MEM_freeN(qtexport->audioOutputBuffer);
- MEM_freeN(qtexport->audioOutputPktDesc);
-
- /* Reopen audio file and merge it */
- audioTmpMovie = [QTMovie movieWithFile:qtexport->audioFileName error:&error];
- if (audioTmpMovie) {
- NSArray *audioTracks = [audioTmpMovie tracksOfMediaType:QTMediaTypeSound];
- QTTrack *audioTrack = nil;
- if ( [audioTracks count] > 0 ) {
- audioTrack = [audioTracks objectAtIndex:0];
- }
-
- if (audioTrack) {
- QTTimeRange totalRange;
- totalRange.time = QTZeroTime;
- totalRange.duration = [[audioTmpMovie attributeForKey:QTMovieDurationAttribute] QTTimeValue];
-
- [qtexport->movie insertSegmentOfTrack:audioTrack timeRange:totalRange atTime:QTZeroTime];
- }
- }
-
- /* Save file */
- dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
- forKey:QTMovieFlatten];
-
- if (dict) {
- [qtexport->movie writeToFile:qtexport->filename withAttributes:dict];
- }
-
- /* Delete temp files */
- fileManager = [[NSFileManager alloc] init];
- [fileManager removeItemAtPath:qtexport->audioFileName error:&error];
- [fileManager removeItemAtPath:qtexport->videoTempFileName error:&error];
- [fileManager release];
- }
- else {
- /* Flush update of the movie file */
- [qtexport->movie updateMovieFile];
-
- [qtexport->movie invalidate];
- }
-
- /* Clean up movie structure */
- if (qtexport->filename) [qtexport->filename release];
- qtexport->filename = nil;
- if (qtexport->audioFileName) [qtexport->audioFileName release];
- qtexport->audioFileName = nil;
- if (qtexport->videoTempFileName) [qtexport->videoTempFileName release];
- qtexport->videoTempFileName = nil;
- [qtexport->frameAttributes release];
- [qtexport->movie release];
- }
-
- [QTMovie exitQTKitOnThread];
- [pool drain];
-}
-
-
-void free_qtcomponentdata(void)
-{
-}
-
-void quicktime_verify_image_type(RenderData *rd, ImageFormatData *imf)
-{
- if (imf->imtype == R_IMF_IMTYPE_QUICKTIME) {
- if ((rd->qtcodecsettings.codecType <= 0) ||
- (rd->qtcodecsettings.codecSpatialQuality < 0) ||
- (rd->qtcodecsettings.codecSpatialQuality > 100))
- {
- rd->qtcodecsettings.codecType = kJPEGCodecType;
- rd->qtcodecsettings.codecSpatialQuality = (codecHighQuality * 100) / codecLosslessQuality;
- }
- if ((rd->qtcodecsettings.audioSampleRate < 21000) ||
- (rd->qtcodecsettings.audioSampleRate > 193000))
- {
- rd->qtcodecsettings.audioSampleRate = 48000;
- }
-
- if (rd->qtcodecsettings.audioBitDepth == 0) {
- rd->qtcodecsettings.audioBitDepth = AUD_FORMAT_S16;
- }
-
- if (rd->qtcodecsettings.audioBitRate == 0) {
- rd->qtcodecsettings.audioBitRate = 256000;
- }
- }
-}
-
-#endif /* _WIN32 || __APPLE__ */
-#endif /* WITH_QUICKTIME */
-
diff --git a/source/blender/quicktime/apple/qtkit_import.m b/source/blender/quicktime/apple/qtkit_import.m
deleted file mode 100644
index ba7ee0a8936..00000000000
--- a/source/blender/quicktime/apple/qtkit_import.m
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Code to use Quicktime to load images/movies as texture.
- *
- * ***** 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 written by Rob Haarsma (phase)
- *
- * Contributor(s): Stefan Gartner (sgefant)
- * Damien Plisson 11/2009
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifdef WITH_QUICKTIME
-
-#include "MEM_guardedalloc.h"
-
-#include "IMB_anim.h"
-#include "BLI_sys_types.h"
-#include "BLI_utildefines.h"
-#include "BKE_global.h"
-
-#include "BLI_dynstr.h"
-#include "BLI_path_util.h"
-
-#import <Cocoa/Cocoa.h>
-#import <QTKit/QTKit.h>
-
-#include "quicktime_import.h"
-#include "quicktime_export.h"
-
-// quicktime structure definition
-// this structure is part of the anim struct
-
-typedef struct _QuicktimeMovie {
- QTMovie *movie;
- QTMedia *media;
-
- long durationTime;
- long durationScale;
- long framecount;
-
-
- ImBuf *ibuf;
-
- long previousPosition;
-
-} QuicktimeMovie;
-
-
-#define QTIME_DEBUG 0
-
-
-void quicktime_init(void)
-{
- G.have_quicktime = true;
-}
-
-void quicktime_exit(void)
-{
- if (G.have_quicktime) {
- free_qtcomponentdata();
- }
-}
-
-
-int anim_is_quicktime(const char *name)
-{
- NSAutoreleasePool *pool;
-
- // don't let quicktime movie import handle these
-
- if (BLI_testextensie_n(
- name,
- ".swf",
- ".txt",
- ".mpg",
- ".vob", /* disabled, vob is essential .mpg, don't handle */
- ".avi", /* wouldn't be appropriate ;) */
- ".mov", /* disabled, suboptimal decoding speed */
- ".mp4", /* disabled, suboptimal decoding speed */
- ".m4v", /* disabled, suboptimal decoding speed */
- ".tga",
- ".png",
- ".bmp",
- ".jpg",
- ".tif",
- ".exr",
- ".wav",
- ".zip",
- ".mp3",
- NULL))
- {
- return 0;
- }
-
- if (QTIME_DEBUG) printf("qt: checking as movie: %s\n", name);
-
- pool = [[NSAutoreleasePool alloc] init];
-
- if ([QTMovie canInitWithFile:[NSString stringWithCString:name
- encoding:[NSString defaultCStringEncoding]]])
- {
- [pool drain];
- return true;
- }
- else
- {
- [pool drain];
- return false;
- }
-}
-
-
-void free_anim_quicktime(struct anim *anim)
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- if (anim == NULL) return;
- if (anim->qtime == NULL) return;
-
- if (anim->qtime->ibuf)
- IMB_freeImBuf(anim->qtime->ibuf);
-
- [anim->qtime->media release];
- [anim->qtime->movie release];
-
- [QTMovie exitQTKitOnThread];
-
- if (anim->qtime) MEM_freeN (anim->qtime);
-
- anim->qtime = NULL;
-
- anim->duration = 0;
-
- [pool drain];
-}
-
-static ImBuf *nsImageToiBuf(NSImage *sourceImage, int width, int height)
-{
- ImBuf *ibuf = NULL;
- uchar *rasterRGB = NULL;
- uchar *rasterRGBA = NULL;
- uchar *toIBuf = NULL;
- int x, y, to_i, from_i;
- NSSize bitmapSize;
- NSBitmapImageRep *blBitmapFormatImageRGB,*blBitmapFormatImageRGBA, *bitmapImage = nil;
- NSEnumerator *enumerator;
- NSImageRep *representation;
-
- ibuf = IMB_allocImBuf(width, height, 32, IB_rect);
- if (!ibuf) {
- if (QTIME_DEBUG) {
- printf("quicktime_import: could not allocate memory for the image.\n");
- }
- return NULL;
- }
-
- /*Get the bitmap of the image*/
- enumerator = [[sourceImage representations] objectEnumerator];
- while ((representation = [enumerator nextObject])) {
- if ([representation isKindOfClass:[NSBitmapImageRep class]]) {
- bitmapImage = (NSBitmapImageRep *)representation;
- break;
- }
- }
- if (bitmapImage == nil) return NULL;
-
- if (([bitmapImage bitsPerPixel] == 32) && (([bitmapImage bitmapFormat] & 0x5) == 0)
- && ![bitmapImage isPlanar]) {
- /* Try a fast copy if the image is a meshed RGBA 32bit bitmap*/
- toIBuf = (uchar *)ibuf->rect;
- rasterRGB = (uchar *)[bitmapImage bitmapData];
- for (y = 0; y < height; y++) {
- to_i = (height-y-1)*width;
- from_i = y*width;
- memcpy(toIBuf+4*to_i, rasterRGB+4*from_i, 4*width);
- }
- }
- else {
-
- bitmapSize.width = width;
- bitmapSize.height = height;
-
- /* Tell cocoa image resolution is same as current system one */
- [bitmapImage setSize:bitmapSize];
-
- /* Convert the image in a RGBA 32bit format */
- /* As Core Graphics does not support contextes with non premutliplied alpha,
- * we need to get alpha key values in a separate batch */
-
- /* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */
- blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
- pixelsWide:width
- pixelsHigh:height
- bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bitmapFormat:0
- bytesPerRow:4*width
- bitsPerPixel:32/*RGB format padded to 32bits*/];
-
- [NSGraphicsContext saveGraphicsState];
- [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]];
- [bitmapImage draw];
- [NSGraphicsContext restoreGraphicsState];
-
- rasterRGB = (uchar *)[blBitmapFormatImageRGB bitmapData];
- if (rasterRGB == NULL) {
- [blBitmapFormatImageRGB release];
- return NULL;
- }
-
- /* Then get Alpha values by getting the RGBA image (that is premultiplied btw) */
- blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
- pixelsWide:width
- pixelsHigh:height
- bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bitmapFormat:0
- bytesPerRow:4*width
- bitsPerPixel:32/* RGBA */];
-
- [NSGraphicsContext saveGraphicsState];
- [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]];
- [bitmapImage draw];
- [NSGraphicsContext restoreGraphicsState];
-
- rasterRGBA = (uchar *)[blBitmapFormatImageRGBA bitmapData];
- if (rasterRGBA == NULL) {
- [blBitmapFormatImageRGB release];
- [blBitmapFormatImageRGBA release];
- return NULL;
- }
-
- /*Copy the image to ibuf, flipping it vertically*/
- toIBuf = (uchar *)ibuf->rect;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- to_i = (height-y-1)*width + x;
- from_i = y*width + x;
-
- toIBuf[4*to_i] = rasterRGB[4*from_i]; /* R */
- toIBuf[4*to_i+1] = rasterRGB[4*from_i+1]; /* G */
- toIBuf[4*to_i+2] = rasterRGB[4*from_i+2]; /* B */
- toIBuf[4*to_i+3] = rasterRGBA[4*from_i+3]; /* A */
- }
- }
-
- [blBitmapFormatImageRGB release];
- [blBitmapFormatImageRGBA release];
- }
-
- return ibuf;
-}
-
-ImBuf *qtime_fetchibuf (struct anim *anim, int position)
-{
- NSImage *frameImage;
- QTTime time;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- ImBuf *ibuf;
-
- if (anim == NULL) {
- return (NULL);
- }
-
- if (position == anim->qtime->previousPosition+1) { //Optimize sequential read
- [anim->qtime->movie stepForward];
- frameImage = [anim->qtime->movie currentFrameImage];
- anim->qtime->previousPosition++;
- }
- else {
- time.timeScale = anim->qtime->durationScale;
- time.timeValue = (anim->qtime->durationTime * position) / anim->qtime->framecount;
-
- [anim->qtime->movie setCurrentTime:time];
- frameImage = [anim->qtime->movie currentFrameImage];
-
- anim->qtime->previousPosition = position;
- }
-
- if (frameImage == nil) {
- if (QTIME_DEBUG) printf ("Error reading frame from Quicktime");
- [pool drain];
- return NULL;
- }
-
- ibuf = nsImageToiBuf(frameImage,anim->x, anim->y);
- [pool drain];
-
- return ibuf;
-}
-
-
-int startquicktime(struct anim *anim)
-{
- NSAutoreleasePool *pool;
- NSArray* videoTracks;
- NSSize frameSize;
- QTTime qtTimeDuration;
- NSDictionary *attributes;
-
- anim->qtime = MEM_callocN(sizeof(QuicktimeMovie),"animqt");
-
- if (anim->qtime == NULL) {
- if (QTIME_DEBUG) printf("Can't alloc qtime: %s\n", anim->name);
- return -1;
- }
-
- pool = [[NSAutoreleasePool alloc] init];
-
- [QTMovie enterQTKitOnThread];
-
- attributes = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSString stringWithCString:anim->name
- encoding:[NSString defaultCStringEncoding]], QTMovieFileNameAttribute,
- [NSNumber numberWithBool:NO], QTMovieEditableAttribute,
- nil];
-
- anim->qtime->movie = [QTMovie movieWithAttributes:attributes error:NULL];
-
- if (!anim->qtime->movie) {
- if (QTIME_DEBUG) printf("qt: bad movie %s\n", anim->name);
- MEM_freeN(anim->qtime);
- if (QTIME_DEBUG) printf("qt: can't load %s\n", anim->name);
- [QTMovie exitQTKitOnThread];
- [pool drain];
- return -1;
- }
- [anim->qtime->movie retain];
-
- // sets Media and Track!
-
- videoTracks = [anim->qtime->movie tracksOfMediaType:QTMediaTypeVideo];
-
- if ([videoTracks count] == 0) {
- if (QTIME_DEBUG) printf("qt: no video tracks for movie %s\n", anim->name);
- [anim->qtime->movie release];
- MEM_freeN(anim->qtime);
- if (QTIME_DEBUG) printf("qt: can't load %s\n", anim->name);
- [QTMovie exitQTKitOnThread];
- [pool drain];
- return -1;
- }
-
- anim->qtime->media = [[videoTracks objectAtIndex:0] media];
- [anim->qtime->media retain];
-
-
- frameSize = [[anim->qtime->movie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
- anim->x = frameSize.width;
- anim->y = frameSize.height;
-
- if (anim->x == 0 && anim->y == 0) {
- if (QTIME_DEBUG) printf("qt: error, no dimensions\n");
- free_anim_quicktime(anim);
- [pool drain];
- return -1;
- }
-
- anim->qtime->ibuf = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect);
-
- qtTimeDuration = [[anim->qtime->media attributeForKey:QTMediaDurationAttribute] QTTimeValue];
- anim->qtime->durationTime = qtTimeDuration.timeValue;
- anim->qtime->durationScale = qtTimeDuration.timeScale;
-
- anim->qtime->framecount = [[anim->qtime->media attributeForKey:QTMediaSampleCountAttribute] longValue];
- anim->qtime->previousPosition = -2; //Force seeking for first read
-
- //fill blender's anim struct
-
- anim->duration = anim->qtime->framecount;
- anim->params = 0;
-
- anim->interlacing = 0;
- anim->orientation = 0;
- anim->framesize = anim->x * anim->y * 4;
-
- anim->curposition = 0;
-
- [pool drain];
-
- return 0;
-}
-
-#endif /* WITH_QUICKTIME */
-
diff --git a/source/blender/quicktime/quicktime_export.h b/source/blender/quicktime/quicktime_export.h
deleted file mode 100644
index aaa3f5c9070..00000000000
--- a/source/blender/quicktime/quicktime_export.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * ***** 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) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/quicktime/quicktime_export.h
- * \ingroup quicktime
- */
-
-
-#ifndef __QUICKTIME_EXPORT_H__
-#define __QUICKTIME_EXPORT_H__
-
-#if defined (_WIN32) || (__APPLE__)
-
-#define __AIFF__
-
-
-#define QTAUDIO_FLAG_RESAMPLE_NOHQ 1
-#define QTAUDIO_FLAG_CODEC_ISCBR 2
-
-
-/*Codec list*/
-typedef struct QuicktimeCodecTypeDesc {
- int codecType;
- int rnatmpvalue;
- const char *codecName;
-} QuicktimeCodecTypeDesc;
-
-// quicktime movie output functions
-struct ImageFormatData;
-struct RenderData;
-struct ReportList;
-struct Scene;
-
-int start_qt(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview, const char *suffix); //for movie handle (BKE writeavi.c now)
-int append_qt(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, const char *suffix, struct ReportList *reports);
-void end_qt(void *context_v);
-void filepath_qt(char *string, struct RenderData *rd, bool preview, const char *suffix);
-void *context_create_qt(void);
-void context_free_qt(void *context_v);
-
-/*RNA helper functions */
-void quicktime_verify_image_type(struct RenderData *rd, struct ImageFormatData *imf); //used by RNA for defaults values init, if needed
-/*Video codec type*/
-int quicktime_get_num_videocodecs(void);
-QuicktimeCodecTypeDesc *quicktime_get_videocodecType_desc(int indexValue);
-int quicktime_rnatmpvalue_from_videocodectype(int codecType);
-int quicktime_videocodecType_from_rnatmpvalue(int rnatmpvalue);
-
-/*Audio codec type*/
-int quicktime_get_num_audiocodecs(void);
-QuicktimeCodecTypeDesc *quicktime_get_audiocodecType_desc(int indexValue);
-int quicktime_rnatmpvalue_from_audiocodectype(int codecType);
-int quicktime_audiocodecType_from_rnatmpvalue(int rnatmpvalue);
-
-void free_qtcomponentdata(void);
-void makeqtstring(struct RenderData *rd, char *string, bool preview); //for playanim.c
-
-
-#ifdef __APPLE__
-//Include the quicktime codec types constants that are missing in QTKitDefines.h
-enum {
- kRawCodecType = 'raw ',
- kCinepakCodecType = 'cvid',
- kGraphicsCodecType = 'smc ',
- kAnimationCodecType = 'rle ',
- kVideoCodecType = 'rpza',
- kComponentVideoCodecType = 'yuv2',
- kJPEGCodecType = 'jpeg',
- kMotionJPEGACodecType = 'mjpa',
- kMotionJPEGBCodecType = 'mjpb',
- kSGICodecType = '.SGI',
- kPlanarRGBCodecType = '8BPS',
- kMacPaintCodecType = 'PNTG',
- kGIFCodecType = 'gif ',
- kPhotoCDCodecType = 'kpcd',
- kQuickDrawGXCodecType = 'qdgx',
- kAVRJPEGCodecType = 'avr ',
- kOpenDMLJPEGCodecType = 'dmb1',
- kBMPCodecType = 'WRLE',
- kWindowsRawCodecType = 'WRAW',
- kVectorCodecType = 'path',
- kQuickDrawCodecType = 'qdrw',
- kWaterRippleCodecType = 'ripl',
- kFireCodecType = 'fire',
- kCloudCodecType = 'clou',
- kH261CodecType = 'h261',
- kH263CodecType = 'h263',
- kDVCNTSCCodecType = 'dvc ', /* DV - NTSC and DVCPRO NTSC (available in QuickTime 6.0 or later)*/
- /* NOTE: kDVCProNTSCCodecType is deprecated. */
- /* Use kDVCNTSCCodecType instead -- as far as the codecs are concerned, */
- /* the two data formats are identical.*/
- kDVCPALCodecType = 'dvcp',
- kDVCProPALCodecType = 'dvpp', /* available in QuickTime 6.0 or later*/
- kDVCPro50NTSCCodecType = 'dv5n',
- kDVCPro50PALCodecType = 'dv5p',
- kDVCPro100NTSCCodecType = 'dv1n',
- kDVCPro100PALCodecType = 'dv1p',
- kDVCPROHD720pCodecType = 'dvhp',
- kDVCPROHD1080i60CodecType = 'dvh6',
- kDVCPROHD1080i50CodecType = 'dvh5',
- kBaseCodecType = 'base',
- kFLCCodecType = 'flic',
- kTargaCodecType = 'tga ',
- kPNGCodecType = 'png ',
- kTIFFCodecType = 'tiff', /* NOTE: despite what might seem obvious from the two constants*/
- /* below and their names, they really are correct. 'yuvu' really */
- /* does mean signed, and 'yuvs' really does mean unsigned. Really. */
- kComponentVideoSigned = 'yuvu',
- kComponentVideoUnsigned = 'yuvs',
- kCMYKCodecType = 'cmyk',
- kMicrosoftVideo1CodecType = 'msvc',
- kSorensonCodecType = 'SVQ1',
- kSorenson3CodecType = 'SVQ3', /* available in QuickTime 5 and later*/
- kIndeo4CodecType = 'IV41',
- kMPEG4VisualCodecType = 'mp4v',
- k64ARGBCodecType = 'b64a',
- k48RGBCodecType = 'b48r',
- k32AlphaGrayCodecType = 'b32a',
- k16GrayCodecType = 'b16g',
- kMpegYUV420CodecType = 'myuv',
- kYUV420CodecType = 'y420',
- kSorensonYUV9CodecType = 'syv9',
- k422YpCbCr8CodecType = '2vuy', /* Component Y'CbCr 8-bit 4:2:2 */
- k444YpCbCr8CodecType = 'v308', /* Component Y'CbCr 8-bit 4:4:4 */
- k4444YpCbCrA8CodecType = 'v408', /* Component Y'CbCrA 8-bit 4:4:4:4 */
- k422YpCbCr16CodecType = 'v216', /* Component Y'CbCr 10,12,14,16-bit 4:2:2*/
- k422YpCbCr10CodecType = 'v210', /* Component Y'CbCr 10-bit 4:2:2 */
- k444YpCbCr10CodecType = 'v410', /* Component Y'CbCr 10-bit 4:4:4 */
- k4444YpCbCrA8RCodecType = 'r408', /* Component Y'CbCrA 8-bit 4:4:4:4, rendering format. full range alpha, zero biased yuv*/
- kJPEG2000CodecType = 'mjp2',
- kPixletCodecType = 'pxlt',
- kH264CodecType = 'avc1'
-};
-#endif
-
-#endif /* (_WIN32) || (__APPLE__) */
-
-#endif /* __QUICKTIME_IMP_H__ */
diff --git a/source/blender/quicktime/quicktime_import.h b/source/blender/quicktime/quicktime_import.h
deleted file mode 100644
index 3c6b2028031..00000000000
--- a/source/blender/quicktime/quicktime_import.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Quicktime_import.h
- *
- *
- * ***** 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) 2002-2003 by TNCCI Inc.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/quicktime/quicktime_import.h
- * \ingroup quicktime
- */
-
-
-
-#ifndef __QUICKTIME_IMPORT_H__
-#define __QUICKTIME_IMPORT_H__
-
-#define __AIFF__
-
-#include "../imbuf/IMB_imbuf.h"
-#include "../imbuf/IMB_imbuf_types.h"
-
-#ifdef _WIN32
-# ifndef __FIXMATH__
-# include <FixMath.h>
-# endif /* __FIXMATH__ */
-#endif /* _WIN32 _ */
-
-/* init/exit */
-
-void quicktime_init(void);
-void quicktime_exit(void);
-
-/* quicktime movie import functions */
-
-int anim_is_quicktime(const char *name);
-int startquicktime(struct anim *anim);
-void free_anim_quicktime(struct anim *anim);
-ImBuf *qtime_fetchibuf(struct anim *anim, int position);
-
-#endif /* __QUICKTIME_IMPORT_H__ */
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index 9e40ab02ee4..27ec6bf8ba6 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -34,7 +34,9 @@ set(INC
../depsgraph
../makesdna
../makesrna
+ ../nodes
../physics
+ ../../../intern/atomic
../../../intern/guardedalloc
../../../intern/mikktspace
../../../intern/smoke/extern
@@ -146,16 +148,6 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
-if(WITH_CODEC_QUICKTIME)
- list(APPEND INC
- ../quicktime
- )
- list(APPEND INC_SYS
- ${QUICKTIME_INCLUDE_DIRS}
- )
- add_definitions(-DWITH_QUICKTIME)
-endif()
-
if(WITH_GAMEENGINE)
add_definitions(-DWITH_GAMEENGINE)
endif()
@@ -164,10 +156,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
-if(WITH_CYCLES AND WITH_CYCLES_DEBUG)
- add_definitions(-DWITH_CYCLES_DEBUG)
-endif()
-
if(APPLE)
# SSE math is enabled by default on x86_64
if(CMAKE_OSX_ARCHITECTURES MATCHES "i386")
diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h
index f83a210275f..52491673612 100644
--- a/source/blender/render/extern/include/RE_engine.h
+++ b/source/blender/render/extern/include/RE_engine.h
@@ -96,6 +96,7 @@ typedef struct RenderEngineType {
void (*view_draw)(struct RenderEngine *engine, const struct bContext *context);
void (*update_script_node)(struct RenderEngine *engine, struct bNodeTree *ntree, struct bNode *node);
+ void (*update_render_passes)(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl);
/* RNA integration */
ExtensionRNA ext;
@@ -139,7 +140,8 @@ void RE_result_load_from_file(struct RenderResult *result, struct ReportList *re
struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname);
void RE_engine_update_result(RenderEngine *engine, struct RenderResult *result);
-void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int merge_results);
+void RE_engine_add_pass(RenderEngine *engine, const char *name, int channels, const char *chan_id, const char *layername);
+void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int highlight, int merge_results);
const char *RE_engine_active_view_get(RenderEngine *engine);
void RE_engine_active_view_set(RenderEngine *engine, const char *viewname);
@@ -160,6 +162,9 @@ bool RE_engine_is_external(struct Render *re);
void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe);
+void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl,
+ const char *name, int channels, const char *chanid, int type);
+
/* Engine Types */
void RE_engines_init(void);
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index 7021477a702..cf9298bdb9e 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -83,24 +83,19 @@ typedef struct RenderView {
typedef struct RenderPass {
struct RenderPass *next, *prev;
- int passtype, channels;
+ int channels;
char name[64]; /* amount defined in openexr_multi.h */
char chan_id[8]; /* amount defined in openexr_multi.h */
float *rect;
int rectx, recty;
- char internal_name[64]; /* EXR_PASS_MAXNAME */
+ char fullname[64]; /* EXR_PASS_MAXNAME */
char view[64]; /* EXR_VIEW_MAXNAME */
int view_id; /* quick lookup */
- int debug_type;
+ int pad;
} RenderPass;
-enum {
- RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS = 0,
- RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES = 1,
- RENDER_PASS_DEBUG_RAY_BOUNCES = 2,
-};
/* a renderlayer is a full image, but with all passes and samples */
/* size of the rects is defined in RenderResult */
@@ -199,6 +194,10 @@ typedef struct RenderStats {
struct Render *RE_NewRender(const char *name);
struct Render *RE_GetRender(const char *name);
+struct Scene;
+struct Render *RE_NewSceneRender(const struct Scene *scene);
+struct Render *RE_GetSceneRender(const struct Scene *scene);
+
/* assign default dummy callbacks */
void RE_InitRenderCB(struct Render *re);
@@ -235,7 +234,7 @@ void RE_render_result_rect_from_ibuf(
struct ImBuf *ibuf, const int view_id);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
-float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname);
+float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, const char *name, const char *viewname);
/* add passes for grease pencil */
struct RenderPass *RE_create_gp_pass(struct RenderResult *rr, const char *layername, const char *viewname);
@@ -344,6 +343,7 @@ int RE_seq_render_active(struct Scene *scene, struct RenderData *rd);
bool RE_layers_have_name(struct RenderResult *result);
+struct RenderPass *RE_pass_find_by_name(volatile struct RenderLayer *rl, const char *name, const char *viewname);
struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname);
/* shaded view or baking options */
@@ -380,7 +380,7 @@ bool RE_allow_render_generic_object(struct Object *ob);
/* RE_updateRenderInstances flag */
enum {
RE_OBJECT_INSTANCES_UPDATE_VIEW = (1 << 0),
- RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1),
+ RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1)
};
void RE_updateRenderInstances(Render *re, int flag);
@@ -393,13 +393,5 @@ struct RenderView *RE_RenderViewGetByName(struct RenderResult *res, const char *
RenderResult *RE_DuplicateRenderResult(RenderResult *rr);
-/******* Debug pass helper functions *********/
-
-#ifdef WITH_CYCLES_DEBUG
-int RE_debug_pass_num_channels_get(int pass_type);
-const char *RE_debug_pass_name_get(int pass_type);
-int RE_debug_pass_type_get(struct Render *re);
-#endif
-
#endif /* __RE_PIPELINE_H__ */
diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h
index 2b5d0ca4e14..1779ccc5d19 100644
--- a/source/blender/render/extern/include/RE_render_ext.h
+++ b/source/blender/render/extern/include/RE_render_ext.h
@@ -45,7 +45,7 @@ struct Scene;
/* render_texture.c */
/* used by particle.c, effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */
int externtex(
- struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta,
+ const struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta,
const int thread, struct ImagePool *pool, const bool skip_load_image, const bool texnode_preview);
void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype);
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype);
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index 73867de6b2e..b64c0c8fc52 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -178,6 +178,7 @@ typedef struct ShadeInput {
unsigned int lay;
int layflag, passflag, combinedflag;
+ short object_pass_index;
struct Group *light_override;
struct Material *mat_override;
@@ -218,6 +219,8 @@ int multitex_nodes(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3],
float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]);
void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]);
+float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta);
+
/* shaded view and bake */
struct Render;
struct Image;
@@ -239,6 +242,9 @@ enum {
const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4];
+float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi);
+float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi);
+
enum {
RE_VIEW_MATRIX,
RE_VIEWINV_MATRIX,
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 0c4f4e20325..4057d8c1052 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -67,6 +67,11 @@ void render_result_views_new(struct RenderResult *rr, struct RenderData *rd);
void render_result_merge(struct RenderResult *rr, struct RenderResult *rrpart);
+/* Add Passes */
+
+void render_result_clone_passes(struct Render *re, struct RenderResult *rr, const char *viewname);
+void render_result_add_pass(struct RenderResult *rr, const char *name, int channels, const char *chan_id, const char *layername, const char *viewname);
+
/* Free */
void render_result_free(struct RenderResult *rr);
@@ -84,7 +89,7 @@ void render_result_exr_file_begin(struct Render *re);
void render_result_exr_file_end(struct Render *re);
/* render pass wrapper for gpencil */
-struct RenderPass *gp_add_pass(struct RenderResult *rr, struct RenderLayer *rl, int channels, int passtype, const char *viewname);
+struct RenderPass *gp_add_pass(struct RenderResult *rr, struct RenderLayer *rl, int channels, const char *name, const char *viewname);
void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart, const char *viewname);
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index b3a5ccdae17..f9942bef61f 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -335,7 +335,7 @@ typedef struct ObjectRen {
char (*mcol)[MAX_CUSTOMDATA_LAYER_NAME];
int actmtface, actmcol, bakemtface;
- char tangent_mask; /* which tangent layer should be calculated */
+ short tangent_mask; /* which tangent layer should be calculated */
float obmat[4][4]; /* only used in convertblender.c, for instancing */
@@ -382,6 +382,8 @@ typedef struct ObjectInstanceRen {
float part_co[3];
float part_vel[3];
float part_avel[3];
+
+ unsigned int random_id;
} ObjectInstanceRen;
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
index 7254fd25ee6..f4c4a50ac27 100644
--- a/source/blender/render/intern/include/rendercore.h
+++ b/source/blender/render/intern/include/rendercore.h
@@ -34,6 +34,12 @@
#include "render_types.h"
+#include "RE_engine.h"
+
+#include "DNA_node_types.h"
+
+#include "NOD_composite.h"
+
struct ShadeInput;
struct ShadeResult;
struct World;
@@ -77,6 +83,8 @@ void zbufshade_sss_tile(struct RenderPart *pa);
int get_sample_layers(struct RenderPart *pa, struct RenderLayer *rl, struct RenderLayer **rlpp);
+void render_internal_update_passes(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl);
+
/* -------- ray.c ------- */
diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h
index 27867eadbb4..3ef6e9d7476 100644
--- a/source/blender/render/intern/include/shading.h
+++ b/source/blender/render/intern/include/shading.h
@@ -57,7 +57,7 @@ typedef struct ShadeSample {
void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr);
void shade_input_set_triangle_i(struct ShadeInput *shi, struct ObjectInstanceRen *obi, struct VlakRen *vlr, short i1, short i2, short i3);
-void shade_input_set_triangle(struct ShadeInput *shi, volatile int obi, volatile int facenr, int normal_flip);
+void shade_input_set_triangle(struct ShadeInput *shi, int obi, int facenr, int normal_flip);
void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from);
void shade_input_calc_viewco(struct ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3]);
void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float sx, float sy, float z);
@@ -99,7 +99,7 @@ ListBase *get_lights(struct ShadeInput *shi);
float lamp_get_visibility(struct LampRen *lar, const float co[3], float lv[3], float *dist);
void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float shadfac[4], int do_real);
-float fresnel_fac(const float view[3], const float vn[3], float fresnel, float fac);
+float fresnel_fac(const float view[3], const float vn[3], float fresnel, float fac);
/* rayshade.c */
extern void shade_ray(struct Isect *is, struct ShadeInput *shi, struct ShadeResult *shr);
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
index 81e41a20f2e..103fa3e6034 100644
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
@@ -59,6 +59,7 @@ static void rtbuild_init(RTBuilder *b)
b->primitives.begin = NULL;
b->primitives.end = NULL;
b->primitives.maxsize = 0;
+ b->depth = 0;
for (int i = 0; i < RTBUILD_MAX_CHILDS; i++)
b->child_offset[i] = 0;
@@ -178,6 +179,8 @@ RTBuilder *rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp)
{
rtbuild_init(tmp);
+ tmp->depth = b->depth + 1;
+
for (int i = 0; i < 3; i++)
if (b->sorted_begin[i]) {
tmp->sorted_begin[i] = b->sorted_begin[i] + b->child_offset[child];
@@ -336,6 +339,15 @@ int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds)
int baxis = -1, boffset = 0;
if (size > nchilds) {
+ if (b->depth > RTBUILD_MAX_SAH_DEPTH) {
+ // for degenerate cases we avoid running out of stack space
+ // by simply splitting the children in the middle
+ b->child_offset[0] = 0;
+ b->child_offset[1] = (size+1)/2;
+ b->child_offset[2] = size;
+ return 2;
+ }
+
float bcost = FLT_MAX;
baxis = -1;
boffset = size / 2;
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.h b/source/blender/render/intern/raytrace/rayobject_rtbuild.h
index 9e296da144b..83042ef3d7e 100644
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.h
+++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.h
@@ -49,7 +49,8 @@ extern "C" {
* generate with simple calls, and then convert to the theirs
* specific structure on the fly.
*/
-#define RTBUILD_MAX_CHILDS 32
+#define RTBUILD_MAX_CHILDS 32
+#define RTBUILD_MAX_SAH_DEPTH 256
typedef struct RTBuilder {
@@ -79,6 +80,8 @@ typedef struct RTBuilder {
float bb[6];
+ /* current depth */
+ int depth;
} RTBuilder;
/* used during creation */
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index 73424a4e846..588c327ab91 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -684,6 +684,10 @@ void RE_bake_pixels_populate(
int mat_nr = mp->mat_nr;
int image_id = bake_images->lookup[mat_nr];
+ if (image_id < 0) {
+ continue;
+ }
+
bd.bk_image = &bake_images->data[image_id];
bd.primitive_id = ++p_id;
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 86961cdd169..fd46acc3638 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -271,7 +271,7 @@ static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr, int do_tangent)
}
else return;
- tangent_from_uv(uv1, uv2, uv3, v1->co, v2->co, v3->co, vlr->n, tang);
+ tangent_from_uv_v3(uv1, uv2, uv3, v1->co, v2->co, v3->co, vlr->n, tang);
if (do_tangent) {
tav= RE_vertren_get_tangent(obr, v1, 1);
@@ -283,7 +283,7 @@ static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr, int do_tangent)
}
if (v4) {
- tangent_from_uv(uv1, uv3, uv4, v1->co, v3->co, v4->co, vlr->n, tang);
+ tangent_from_uv_v3(uv1, uv3, uv4, v1->co, v3->co, v4->co, vlr->n, tang);
if (do_tangent) {
tav= RE_vertren_get_tangent(obr, v1, 1);
@@ -398,7 +398,7 @@ static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_verte
float *n4= (vlr->v4)? vlr->v4->n: NULL;
const float *c4= (vlr->v4)? vlr->v4->co: NULL;
- accumulate_vertex_normals(vlr->v1->n, vlr->v2->n, vlr->v3->n, n4,
+ accumulate_vertex_normals_v3(vlr->v1->n, vlr->v2->n, vlr->v3->n, n4,
vlr->n, vlr->v1->co, vlr->v2->co, vlr->v3->co, c4);
}
if (do_tangent) {
@@ -3439,10 +3439,9 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
if (need_nmap_tangent_concrete || need_tangent) {
int uv_start = CustomData_get_layer_index(&dm->faceData, CD_MTFACE);
int uv_index = CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, layer->name);
- BLI_assert(uv_start >= 0 && uv_index >= 0);
- if ((uv_start < 0 || uv_index < 0))
- continue;
- int n = uv_index - uv_start;
+
+ /* if there are no UVs, orco tangents are in first slot */
+ int n = (uv_start >= 0 && uv_index >= 0) ? uv_index - uv_start : 0;
const float *tangent = (const float *) layer->data;
float *ftang = RE_vlakren_get_nmap_tangent(obr, vlr, n, true);
@@ -4658,14 +4657,22 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
index= (dob)? dob->persistent_id[0]: 0;
+ /* It seems that we may generate psys->renderdata recursively in some nasty intricated cases of
+ * several levels of bupliobject (see T51524).
+ * For now, basic rule is, do not restore psys if it was already in 'render state'.
+ * Another, more robust solution could be to add some reference counting to that renderdata... */
+ bool psys_has_renderdata = false;
+
/* the emitter has to be processed first (render levels of modifiers) */
/* so here we only check if the emitter should be rendered */
if (ob->particlesystem.first) {
show_emitter= 0;
for (psys=ob->particlesystem.first; psys; psys=psys->next) {
show_emitter += psys->part->draw & PART_DRAW_EMITTER;
- if (!(re->r.scemode & R_VIEWPORT_PREVIEW))
+ if (!(re->r.scemode & R_VIEWPORT_PREVIEW)) {
+ psys_has_renderdata |= (psys->renderdata != NULL);
psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset);
+ }
}
/* if no psys has "show emitter" selected don't render emitter */
@@ -4712,8 +4719,9 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
if (dob)
psys->flag |= PSYS_USE_IMAT;
init_render_object_data(re, obr, timeoffset);
- if (!(re->r.scemode & R_VIEWPORT_PREVIEW))
+ if (!(re->r.scemode & R_VIEWPORT_PREVIEW) && !psys_has_renderdata) {
psys_render_restore(ob, psys);
+ }
psys->flag &= ~PSYS_USE_IMAT;
/* only add instance for objects that have not been used for dupli */
@@ -5569,12 +5577,17 @@ static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *ve
/* interpolate speed vectors from strand surface */
face= mesh->face[*index];
- co1= mesh->co[face[0]];
- co2= mesh->co[face[1]];
- co3= mesh->co[face[2]];
- co4= (face[3])? mesh->co[face[3]]: NULL;
+ co1 = mesh->co[face[0]];
+ co2 = mesh->co[face[1]];
+ co3 = mesh->co[face[2]];
- interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co);
+ if (face[3]) {
+ co4 = mesh->co[face[3]];
+ interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co);
+ }
+ else {
+ interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co);
+ }
zero_v4(speed);
madd_v4_v4fl(speed, winspeed[face[0]], w[0]);
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index d97e18d6511..156b4215992 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -61,6 +61,7 @@
#include "renderpipeline.h"
#include "texture.h"
#include "zbuf.h"
+#include "render_result.h"
/* ------------------------------------------------------------------------- */
@@ -142,8 +143,8 @@ static Render *envmap_render_copy(Render *re, EnvMap *env)
/* set up renderdata */
render_copy_renderdata(&envre->r, &re->r);
envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
- BLI_listbase_clear(&envre->r.layers);
- BLI_listbase_clear(&envre->r.views);
+ BLI_freelistN(&envre->r.layers);
+ BLI_freelistN(&envre->r.views);
envre->r.filtertype = 0;
envre->r.tilex = envre->r.xsch / 2;
envre->r.tiley = envre->r.ysch / 2;
@@ -493,13 +494,20 @@ static void render_envmap(Render *re, EnvMap *env)
env_rotate_scene(envre, tmat, 0);
if (re->test_break(re->tbh) == 0) {
- RenderLayer *rl = envre->result->layers.first;
int y;
float *alpha;
float *rect;
+ if (envre->result->do_exr_tile) {
+ BLI_rw_mutex_lock(&envre->resultmutex, THREAD_LOCK_WRITE);
+ render_result_exr_file_end(envre);
+ BLI_rw_mutex_unlock(&envre->resultmutex);
+ }
+
+ RenderLayer *rl = envre->result->layers.first;
+
/* envmap is rendered independently of multiview */
- rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, "");
+ rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, "");
ibuf = IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect | IB_rectfloat);
memcpy(ibuf->rect_float, rect, ibuf->channels * ibuf->x * ibuf->y * sizeof(float));
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index fd9d95c63b6..a581f7bd198 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -62,13 +62,14 @@
#include "renderpipeline.h"
#include "render_types.h"
#include "render_result.h"
+#include "rendercore.h"
/* Render Engine Types */
static RenderEngineType internal_render_type = {
NULL, NULL,
"BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL,
- NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, render_internal_update_passes,
{NULL, NULL, NULL}
};
@@ -77,7 +78,7 @@ static RenderEngineType internal_render_type = {
static RenderEngineType internal_game_type = {
NULL, NULL,
"BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME,
- NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
{NULL, NULL, NULL}
};
@@ -212,6 +213,8 @@ RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w,
/* can be NULL if we CLAMP the width or height to 0 */
if (result) {
+ render_result_clone_passes(re, result, viewname);
+
RenderPart *pa;
/* Copy EXR tile settings, so pipeline knows whether this is a result
@@ -245,7 +248,18 @@ void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
}
}
-void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel, int merge_results)
+void RE_engine_add_pass(RenderEngine *engine, const char *name, int channels, const char *chan_id, const char *layername)
+{
+ Render *re = engine->re;
+
+ if (!re || !re->result) {
+ return;
+ }
+
+ render_result_add_pass(re->result, name, channels, chan_id, layername, NULL);
+}
+
+void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel, int highlight, int merge_results)
{
Render *re = engine->re;
@@ -254,7 +268,7 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel
}
/* merge. on break, don't merge in result for preview renders, looks nicer */
- if (!cancel) {
+ if (!highlight) {
/* for exr tile render, detect tiles that are done */
RenderPart *pa = get_part_from_result(re, result);
@@ -760,3 +774,22 @@ int RE_engine_render(Render *re, int do_all)
return 1;
}
+void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl,
+ const char *name, int UNUSED(channels), const char *UNUSED(chanid), int type)
+{
+ /* The channel information is currently not used, but is part of the API in case it's needed in the future. */
+
+ if (!(scene && srl && engine)) {
+ return;
+ }
+
+ /* Register the pass in all scenes that have a render layer node for this layer.
+ * Since multiple scenes can be used in the compositor, the code must loop over all scenes
+ * and check whether their nodetree has a node that needs to be updated. */
+ Scene *sce;
+ for (sce = G.main->scene.first; sce; sce = sce->id.next) {
+ if (sce->nodetree) {
+ ntreeCompositRegisterPass(sce->nodetree, scene, srl, name, type);
+ }
+ }
+}
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index 04010522c12..ae02cf56b88 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -1172,7 +1172,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
a = max_ff(a, 1.0f);
b = max_ff(b, 1.0f);
fProbes = 2.f*(a / b) - 1.f;
- AFD.iProbes = iroundf(fProbes);
+ AFD.iProbes = round_fl_to_int(fProbes);
AFD.iProbes = MIN2(AFD.iProbes, tex->afmax);
if (AFD.iProbes < fProbes)
b = 2.f*a / (float)(AFD.iProbes + 1);
@@ -1277,7 +1277,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
b = max_ff(b, 1.0f);
fProbes = 2.f*(a / b) - 1.f;
/* no limit to number of Probes here */
- AFD.iProbes = iroundf(fProbes);
+ AFD.iProbes = round_fl_to_int(fProbes);
if (AFD.iProbes < fProbes) b = 2.f*a / (float)(AFD.iProbes + 1);
AFD.majrad = a/ff;
AFD.minrad = b/ff;
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index 970a3937657..fbf18405093 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -48,10 +48,6 @@
#include "BKE_camera.h"
-#ifdef WITH_QUICKTIME
-#include "quicktime_export.h"
-#endif
-
/* this module */
#include "renderpipeline.h"
#include "render_types.h"
diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c
index b3d31e3b93a..cd93898d846 100644
--- a/source/blender/render/intern/source/occlusion.c
+++ b/source/blender/render/intern/source/occlusion.c
@@ -329,7 +329,7 @@ static void occ_face(const OccFace *face, float co[3], float normal[3], float *a
if (vlr->v4)
mid_v3_v3v3(co, vlr->v1->co, vlr->v3->co);
else
- cent_tri_v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co);
+ mid_v3_v3v3v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co);
if (obi->flag & R_TRANSFORMED)
mul_m4_v3(obi->mat, co);
@@ -1190,9 +1190,14 @@ static void sample_occ_surface(ShadeInput *shi)
co1 = mesh->co[face[0]];
co2 = mesh->co[face[1]];
co3 = mesh->co[face[2]];
- co4 = (face[3]) ? mesh->co[face[3]] : NULL;
- interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co);
+ if (face[3]) {
+ co4 = mesh->co[face[3]];
+ interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co);
+ }
+ else {
+ interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co);
+ }
zero_v3(shi->ao);
zero_v3(shi->env);
@@ -1245,7 +1250,7 @@ static void *exec_strandsurface_sample(void *data)
normal_quad_v3(n, co1, co2, co3, co4);
}
else {
- cent_tri_v3(co, co1, co2, co3);
+ mid_v3_v3v3v3(co, co1, co2, co3);
normal_tri_v3(n, co1, co2, co3);
}
negate_v3(n);
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 9f1ae4a96e0..a0ebe241569 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -74,6 +74,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
+#include "BKE_sound.h"
#include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */
#include "BKE_object.h"
@@ -238,9 +239,9 @@ void RE_FreeRenderResult(RenderResult *res)
render_result_free(res);
}
-float *RE_RenderLayerGetPass(volatile RenderLayer *rl, int passtype, const char *viewname)
+float *RE_RenderLayerGetPass(volatile RenderLayer *rl, const char *name, const char *viewname)
{
- RenderPass *rpass = RE_pass_find_by_type(rl, passtype, viewname);
+ RenderPass *rpass = RE_pass_find_by_name(rl, name, viewname);
return rpass ? rpass->rect : NULL;
}
@@ -306,7 +307,6 @@ Render *RE_GetRender(const char *name)
return re;
}
-
/* if you want to know exactly what has been done */
RenderResult *RE_AcquireResultRead(Render *re)
{
@@ -381,13 +381,13 @@ void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
if (rl) {
if (rv->rectf == NULL) {
for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) {
- rview->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rview->name);
+ rview->rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, rview->name);
}
}
if (rv->rectz == NULL) {
for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) {
- rview->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rview->name);
+ rview->rectz = RE_RenderLayerGetPass(rl, RE_PASSNAME_Z, rview->name);
}
}
}
@@ -441,10 +441,10 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
if (rl) {
if (rv->rectf == NULL)
- rr->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rv->name);
+ rr->rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, rv->name);
if (rv->rectz == NULL)
- rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rv->name);
+ rr->rectz = RE_RenderLayerGetPass(rl, RE_PASSNAME_Z, rv->name);
}
rr->have_combined = (rv->rectf != NULL);
@@ -513,6 +513,36 @@ Render *RE_NewRender(const char *name)
return re;
}
+/* MAX_ID_NAME + sizeof(Library->name) + space + null-terminator. */
+#define MAX_SCENE_RENDER_NAME (MAX_ID_NAME + 1024 + 2)
+
+static void scene_render_name_get(const Scene *scene,
+ const size_t max_size,
+ char *render_name)
+{
+ if (ID_IS_LINKED_DATABLOCK(scene)) {
+ BLI_snprintf(render_name, max_size, "%s %s",
+ scene->id.lib->id.name, scene->id.name);
+ }
+ else {
+ BLI_snprintf(render_name, max_size, "%s", scene->id.name);
+ }
+}
+
+Render *RE_GetSceneRender(const Scene *scene)
+{
+ char render_name[MAX_SCENE_RENDER_NAME];
+ scene_render_name_get(scene, sizeof(render_name), render_name);
+ return RE_GetRender(render_name);
+}
+
+Render *RE_NewSceneRender(const Scene *scene)
+{
+ char render_name[MAX_SCENE_RENDER_NAME];
+ scene_render_name_get(scene, sizeof(render_name), render_name);
+ return RE_NewRender(render_name);
+}
+
/* called for new renders and when finishing rendering so
* we always have valid callbacks on a render */
void RE_InitRenderCB(Render *re)
@@ -722,6 +752,8 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->r.size = source->r.size;
}
+ re_init_resolution(re, source, winx, winy, disprect);
+
/* disable border if it's a full render anyway */
if (re->r.border.xmin == 0.0f && re->r.border.xmax == 1.0f &&
re->r.border.ymin == 0.0f && re->r.border.ymax == 1.0f)
@@ -729,8 +761,6 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->r.mode &= ~R_BORDER;
}
- re_init_resolution(re, source, winx, winy, disprect);
-
if (re->rectx < 1 || re->recty < 1 || (BKE_imtype_is_movie(rd->im_format.imtype) &&
(re->rectx < 16 || re->recty < 16) ))
{
@@ -841,7 +871,7 @@ static void render_result_rescale(Render *re)
if (src_rectf == NULL) {
RenderLayer *rl = render_get_active_layer(re, re->result);
if (rl != NULL) {
- src_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL);
+ src_rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, NULL);
}
}
@@ -860,7 +890,7 @@ static void render_result_rescale(Render *re)
RenderLayer *rl;
rl = render_get_active_layer(re, re->result);
if (rl != NULL) {
- dst_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL);
+ dst_rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, NULL);
}
}
@@ -1654,7 +1684,7 @@ static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float b
/* passes are allocated in sync */
rpass1 = rl1->passes.first;
for (rpass = rl->passes.first; rpass && rpass1; rpass = rpass->next, rpass1 = rpass1->next) {
- if ((rpass->passtype & SCE_PASS_COMBINED) && key_alpha)
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && key_alpha)
addblur_rect_key(rr, rpass->rect, rpass1->rect, blurfac);
else
addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels);
@@ -1854,6 +1884,8 @@ static void render_result_uncrop(Render *re)
rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
+ render_result_clone_passes(re, rres, NULL);
+
render_result_merge(rres, re->result);
render_result_free(re->result);
re->result = rres;
@@ -1910,7 +1942,7 @@ static void do_render_fields_blur_3d(Render *re)
*/
static void render_scene(Render *re, Scene *sce, int cfra)
{
- Render *resc = RE_NewRender(sce->id.name);
+ Render *resc = RE_NewSceneRender(sce);
int winx = re->winx, winy = re->winy;
sce->r.cfra = cfra;
@@ -2345,7 +2377,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
tag_scenes_for_render(re);
for (sce = re->main->scene.first; sce; sce = sce->id.next) {
if (sce->id.tag & LIB_TAG_DOIT) {
- re1 = RE_GetRender(sce->id.name);
+ re1 = RE_GetSceneRender(sce);
if (re1 && (re1->r.scemode & R_FULL_SAMPLE)) {
if (sample) {
@@ -3439,7 +3471,7 @@ bool RE_WriteRenderViewsMovie(
ok = mh->append_movie(movie_ctx_arr[0], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra, (int *) ibuf_arr[2]->rect,
ibuf_arr[2]->x, ibuf_arr[2]->y, "", reports);
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < 3; i++) {
/* imbuf knows which rects are not part of ibuf */
IMB_freeImBuf(ibuf_arr[i]);
}
@@ -3791,6 +3823,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
re->flag &= ~R_ANIMATION;
BLI_callback_exec(re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE);
+ BKE_sound_reset_scene_specs(scene);
/* UGLY WARNING */
G.is_rendering = false;
@@ -3854,9 +3887,9 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
scene = scenode;
/* get render: it can be called from UI with draw callbacks */
- re = RE_GetRender(scene->id.name);
+ re = RE_GetSceneRender(scene);
if (re == NULL)
- re = RE_NewRender(scene->id.name);
+ re = RE_NewSceneRender(scene);
RE_InitState(re, NULL, &scene->r, NULL, winx, winy, &disprect);
re->scene = scene;
re->scene_color_manage = BKE_scene_check_color_management_enabled(scene);
@@ -3885,7 +3918,7 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char
/* multiview: since the API takes no 'view', we use the first combined pass found */
for (rpass = layer->passes.first; rpass; rpass = rpass->next)
- if (rpass->passtype == SCE_PASS_COMBINED)
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED))
break;
if (rpass == NULL)
@@ -4011,13 +4044,12 @@ bool RE_layers_have_name(struct RenderResult *rr)
return false;
}
-RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname)
+RenderPass *RE_pass_find_by_name(volatile RenderLayer *rl, const char *name, const char *viewname)
{
RenderPass *rp = NULL;
for (rp = rl->passes.last; rp; rp = rp->prev) {
- if (rp->passtype == passtype) {
-
+ if (STREQ(rp->name, name)) {
if (viewname == NULL || viewname[0] == '\0')
break;
else if (STREQ(rp->view, viewname))
@@ -4027,6 +4059,50 @@ RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const c
return rp;
}
+/* Only provided for API compatibility, don't use this in new code! */
+RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname)
+{
+#define CHECK_PASS(NAME) \
+ if (passtype == SCE_PASS_ ## NAME) \
+ return RE_pass_find_by_name(rl, RE_PASSNAME_ ## NAME, viewname);
+
+ CHECK_PASS(COMBINED);
+ CHECK_PASS(Z);
+ CHECK_PASS(VECTOR);
+ CHECK_PASS(NORMAL);
+ CHECK_PASS(UV);
+ CHECK_PASS(RGBA);
+ CHECK_PASS(EMIT);
+ CHECK_PASS(DIFFUSE);
+ CHECK_PASS(SPEC);
+ CHECK_PASS(SHADOW);
+ CHECK_PASS(AO);
+ CHECK_PASS(ENVIRONMENT);
+ CHECK_PASS(INDIRECT);
+ CHECK_PASS(REFLECT);
+ CHECK_PASS(REFRACT);
+ CHECK_PASS(INDEXOB);
+ CHECK_PASS(INDEXMA);
+ CHECK_PASS(MIST);
+ CHECK_PASS(RAYHITS);
+ CHECK_PASS(DIFFUSE_DIRECT);
+ CHECK_PASS(DIFFUSE_INDIRECT);
+ CHECK_PASS(DIFFUSE_COLOR);
+ CHECK_PASS(GLOSSY_DIRECT);
+ CHECK_PASS(GLOSSY_INDIRECT);
+ CHECK_PASS(GLOSSY_COLOR);
+ CHECK_PASS(TRANSM_DIRECT);
+ CHECK_PASS(TRANSM_INDIRECT);
+ CHECK_PASS(TRANSM_COLOR);
+ CHECK_PASS(SUBSURFACE_DIRECT);
+ CHECK_PASS(SUBSURFACE_INDIRECT);
+ CHECK_PASS(SUBSURFACE_COLOR);
+
+#undef CHECK_PASS
+
+ return NULL;
+}
+
/* create a renderlayer and renderpass for grease pencil layer */
RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const char *viewname)
{
@@ -4044,7 +4120,7 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha
}
/* clear previous pass if exist or the new image will be over previous one*/
- RenderPass *rp = RE_pass_find_by_type(rl, SCE_PASS_COMBINED, viewname);
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
if (rp) {
if (rp->rect) {
MEM_freeN(rp->rect);
@@ -4052,5 +4128,5 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha
BLI_freelinkN(&rl->passes, rp);
}
/* create a totally new pass */
- return gp_add_pass(rr, rl, 4, SCE_PASS_COMBINED, viewname);
+ return gp_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, viewname);
}
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index a03ea9cb896..fb047aad897 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -983,11 +983,12 @@ void RE_point_density_minmax(
}
else {
float radius[3] = {pd->radius, pd->radius, pd->radius};
- float *loc, *size;
+ BoundBox *bb = BKE_object_boundbox_get(object);
- if (BKE_object_obdata_texspace_get(pd->object, NULL, &loc, &size, NULL)) {
- sub_v3_v3v3(r_min, loc, size);
- add_v3_v3v3(r_max, loc, size);
+ if (bb != NULL) {
+ BLI_assert((bb->flag & BOUNDBOX_DIRTY) == 0);
+ copy_v3_v3(r_min, bb->vec[0]);
+ copy_v3_v3(r_max, bb->vec[6]);
/* Adjust texture space to include density points on the boundaries. */
sub_v3_v3(r_min, radius);
add_v3_v3(r_max, radius);
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 2be6238eeec..8e6e6c9bb7d 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -173,363 +173,72 @@ void render_result_views_shallowdelete(RenderResult *rr)
}
}
-static const char *name_from_passtype(int passtype, int channel)
-{
- if (passtype == SCE_PASS_COMBINED) {
- if (channel == -1) return "Combined";
- if (channel == 0) return "Combined.R";
- if (channel == 1) return "Combined.G";
- if (channel == 2) return "Combined.B";
- return "Combined.A";
- }
- if (passtype == SCE_PASS_Z) {
- if (channel == -1) return "Depth";
- return "Depth.Z";
- }
- if (passtype == SCE_PASS_VECTOR) {
- if (channel == -1) return "Vector";
- if (channel == 0) return "Vector.X";
- if (channel == 1) return "Vector.Y";
- if (channel == 2) return "Vector.Z";
- return "Vector.W";
- }
- if (passtype == SCE_PASS_NORMAL) {
- if (channel == -1) return "Normal";
- if (channel == 0) return "Normal.X";
- if (channel == 1) return "Normal.Y";
- return "Normal.Z";
- }
- if (passtype == SCE_PASS_UV) {
- if (channel == -1) return "UV";
- if (channel == 0) return "UV.U";
- if (channel == 1) return "UV.V";
- return "UV.A";
- }
- if (passtype == SCE_PASS_RGBA) {
- if (channel == -1) return "Color";
- if (channel == 0) return "Color.R";
- if (channel == 1) return "Color.G";
- if (channel == 2) return "Color.B";
- return "Color.A";
- }
- if (passtype == SCE_PASS_EMIT) {
- if (channel == -1) return "Emit";
- if (channel == 0) return "Emit.R";
- if (channel == 1) return "Emit.G";
- return "Emit.B";
- }
- if (passtype == SCE_PASS_DIFFUSE) {
- if (channel == -1) return "Diffuse";
- if (channel == 0) return "Diffuse.R";
- if (channel == 1) return "Diffuse.G";
- return "Diffuse.B";
- }
- if (passtype == SCE_PASS_SPEC) {
- if (channel == -1) return "Spec";
- if (channel == 0) return "Spec.R";
- if (channel == 1) return "Spec.G";
- return "Spec.B";
- }
- if (passtype == SCE_PASS_SHADOW) {
- if (channel == -1) return "Shadow";
- if (channel == 0) return "Shadow.R";
- if (channel == 1) return "Shadow.G";
- return "Shadow.B";
- }
- if (passtype == SCE_PASS_AO) {
- if (channel == -1) return "AO";
- if (channel == 0) return "AO.R";
- if (channel == 1) return "AO.G";
- return "AO.B";
- }
- if (passtype == SCE_PASS_ENVIRONMENT) {
- if (channel == -1) return "Env";
- if (channel == 0) return "Env.R";
- if (channel == 1) return "Env.G";
- return "Env.B";
- }
- if (passtype == SCE_PASS_INDIRECT) {
- if (channel == -1) return "Indirect";
- if (channel == 0) return "Indirect.R";
- if (channel == 1) return "Indirect.G";
- return "Indirect.B";
- }
- if (passtype == SCE_PASS_REFLECT) {
- if (channel == -1) return "Reflect";
- if (channel == 0) return "Reflect.R";
- if (channel == 1) return "Reflect.G";
- return "Reflect.B";
- }
- if (passtype == SCE_PASS_REFRACT) {
- if (channel == -1) return "Refract";
- if (channel == 0) return "Refract.R";
- if (channel == 1) return "Refract.G";
- return "Refract.B";
- }
- if (passtype == SCE_PASS_INDEXOB) {
- if (channel == -1) return "IndexOB";
- return "IndexOB.X";
- }
- if (passtype == SCE_PASS_INDEXMA) {
- if (channel == -1) return "IndexMA";
- return "IndexMA.X";
- }
- if (passtype == SCE_PASS_MIST) {
- if (channel == -1) return "Mist";
- return "Mist.Z";
- }
- if (passtype == SCE_PASS_RAYHITS) {
- if (channel == -1) return "Rayhits";
- if (channel == 0) return "Rayhits.R";
- if (channel == 1) return "Rayhits.G";
- return "Rayhits.B";
- }
- if (passtype == SCE_PASS_DIFFUSE_DIRECT) {
- if (channel == -1) return "DiffDir";
- if (channel == 0) return "DiffDir.R";
- if (channel == 1) return "DiffDir.G";
- return "DiffDir.B";
- }
- if (passtype == SCE_PASS_DIFFUSE_INDIRECT) {
- if (channel == -1) return "DiffInd";
- if (channel == 0) return "DiffInd.R";
- if (channel == 1) return "DiffInd.G";
- return "DiffInd.B";
- }
- if (passtype == SCE_PASS_DIFFUSE_COLOR) {
- if (channel == -1) return "DiffCol";
- if (channel == 0) return "DiffCol.R";
- if (channel == 1) return "DiffCol.G";
- return "DiffCol.B";
- }
- if (passtype == SCE_PASS_GLOSSY_DIRECT) {
- if (channel == -1) return "GlossDir";
- if (channel == 0) return "GlossDir.R";
- if (channel == 1) return "GlossDir.G";
- return "GlossDir.B";
- }
- if (passtype == SCE_PASS_GLOSSY_INDIRECT) {
- if (channel == -1) return "GlossInd";
- if (channel == 0) return "GlossInd.R";
- if (channel == 1) return "GlossInd.G";
- return "GlossInd.B";
- }
- if (passtype == SCE_PASS_GLOSSY_COLOR) {
- if (channel == -1) return "GlossCol";
- if (channel == 0) return "GlossCol.R";
- if (channel == 1) return "GlossCol.G";
- return "GlossCol.B";
- }
- if (passtype == SCE_PASS_TRANSM_DIRECT) {
- if (channel == -1) return "TransDir";
- if (channel == 0) return "TransDir.R";
- if (channel == 1) return "TransDir.G";
- return "TransDir.B";
- }
- if (passtype == SCE_PASS_TRANSM_INDIRECT) {
- if (channel == -1) return "TransInd";
- if (channel == 0) return "TransInd.R";
- if (channel == 1) return "TransInd.G";
- return "TransInd.B";
- }
- if (passtype == SCE_PASS_TRANSM_COLOR) {
- if (channel == -1) return "TransCol";
- if (channel == 0) return "TransCol.R";
- if (channel == 1) return "TransCol.G";
- return "TransCol.B";
- }
- if (passtype == SCE_PASS_SUBSURFACE_DIRECT) {
- if (channel == -1) return "SubsurfaceDir";
- if (channel == 0) return "SubsurfaceDir.R";
- if (channel == 1) return "SubsurfaceDir.G";
- return "SubsurfaceDir.B";
- }
- if (passtype == SCE_PASS_SUBSURFACE_INDIRECT) {
- if (channel == -1) return "SubsurfaceInd";
- if (channel == 0) return "SubsurfaceInd.R";
- if (channel == 1) return "SubsurfaceInd.G";
- return "SubsurfaceInd.B";
- }
- if (passtype == SCE_PASS_SUBSURFACE_COLOR) {
- if (channel == -1) return "SubsurfaceCol";
- if (channel == 0) return "SubsurfaceCol.R";
- if (channel == 1) return "SubsurfaceCol.G";
- return "SubsurfaceCol.B";
- }
- return "Unknown";
-}
-static int passtype_from_name(const char *str, int passflag)
+static char* set_pass_name(char *outname, const char *name, int channel, const char *chan_id)
{
- /* We do not really support several pass of the same types, so in case we are opening an EXR file with several pass
- * names detected as same pass type, only return that pass type the first time, and return 'uknown' for the others.
- * See T48466. */
-#define RETURN_PASS(_passtype) return (passflag & (_passtype)) ? 0 : (_passtype)
-
- if (STRPREFIX(str, "Combined"))
- RETURN_PASS(SCE_PASS_COMBINED);
-
- if (STRPREFIX(str, "Depth"))
- RETURN_PASS(SCE_PASS_Z);
-
- if (STRPREFIX(str, "Vector"))
- RETURN_PASS(SCE_PASS_VECTOR);
-
- if (STRPREFIX(str, "Normal"))
- RETURN_PASS(SCE_PASS_NORMAL);
-
- if (STRPREFIX(str, "UV"))
- RETURN_PASS(SCE_PASS_UV);
-
- if (STRPREFIX(str, "Color"))
- RETURN_PASS(SCE_PASS_RGBA);
-
- if (STRPREFIX(str, "Emit"))
- RETURN_PASS(SCE_PASS_EMIT);
-
- if (STRPREFIX(str, "Diffuse"))
- RETURN_PASS(SCE_PASS_DIFFUSE);
-
- if (STRPREFIX(str, "Spec"))
- RETURN_PASS(SCE_PASS_SPEC);
-
- if (STRPREFIX(str, "Shadow"))
- RETURN_PASS(SCE_PASS_SHADOW);
-
- if (STRPREFIX(str, "AO"))
- RETURN_PASS(SCE_PASS_AO);
-
- if (STRPREFIX(str, "Env"))
- RETURN_PASS(SCE_PASS_ENVIRONMENT);
-
- if (STRPREFIX(str, "Indirect"))
- RETURN_PASS(SCE_PASS_INDIRECT);
-
- if (STRPREFIX(str, "Reflect"))
- RETURN_PASS(SCE_PASS_REFLECT);
-
- if (STRPREFIX(str, "Refract"))
- RETURN_PASS(SCE_PASS_REFRACT);
-
- if (STRPREFIX(str, "IndexOB"))
- RETURN_PASS(SCE_PASS_INDEXOB);
-
- if (STRPREFIX(str, "IndexMA"))
- RETURN_PASS(SCE_PASS_INDEXMA);
-
- if (STRPREFIX(str, "Mist"))
- RETURN_PASS(SCE_PASS_MIST);
-
- if (STRPREFIX(str, "RayHits"))
- RETURN_PASS(SCE_PASS_RAYHITS);
-
- if (STRPREFIX(str, "DiffDir"))
- RETURN_PASS(SCE_PASS_DIFFUSE_DIRECT);
-
- if (STRPREFIX(str, "DiffInd"))
- RETURN_PASS(SCE_PASS_DIFFUSE_INDIRECT);
-
- if (STRPREFIX(str, "DiffCol"))
- RETURN_PASS(SCE_PASS_DIFFUSE_COLOR);
-
- if (STRPREFIX(str, "GlossDir"))
- RETURN_PASS(SCE_PASS_GLOSSY_DIRECT);
-
- if (STRPREFIX(str, "GlossInd"))
- RETURN_PASS(SCE_PASS_GLOSSY_INDIRECT);
-
- if (STRPREFIX(str, "GlossCol"))
- RETURN_PASS(SCE_PASS_GLOSSY_COLOR);
-
- if (STRPREFIX(str, "TransDir"))
- RETURN_PASS(SCE_PASS_TRANSM_DIRECT);
-
- if (STRPREFIX(str, "TransInd"))
- RETURN_PASS(SCE_PASS_TRANSM_INDIRECT);
-
- if (STRPREFIX(str, "TransCol"))
- RETURN_PASS(SCE_PASS_TRANSM_COLOR);
-
- if (STRPREFIX(str, "SubsurfaceDir"))
- RETURN_PASS(SCE_PASS_SUBSURFACE_DIRECT);
-
- if (STRPREFIX(str, "SubsurfaceInd"))
- RETURN_PASS(SCE_PASS_SUBSURFACE_INDIRECT);
-
- if (STRPREFIX(str, "SubsurfaceCol"))
- RETURN_PASS(SCE_PASS_SUBSURFACE_COLOR);
-
- return 0;
-
-#undef RETURN_PASS
+ BLI_strncpy(outname, name, EXR_PASS_MAXNAME);
+ if (channel >= 0) {
+ char token[3] = {'.', chan_id[channel], '\0'};
+ strncat(outname, token, EXR_PASS_MAXNAME);
+ }
+ return outname;
}
-
-static void set_pass_name(char *passname, int passtype, int channel, const char *view)
+static void set_pass_full_name(char *fullname, const char *name, int channel, const char *view, const char *chan_id)
{
- const char delims[] = {'.', '\0'};
- const char *sep;
- const char *token;
- size_t len;
-
- const char *passtype_name = name_from_passtype(passtype, channel);
-
- if (view == NULL || view[0] == '\0') {
- BLI_strncpy(passname, passtype_name, EXR_PASS_MAXNAME);
- return;
- }
-
- len = BLI_str_rpartition(passtype_name, delims, &sep, &token);
-
- if (sep) {
- BLI_snprintf(passname, EXR_PASS_MAXNAME, "%.*s.%s.%s", (int)len, passtype_name, view, token);
+ BLI_strncpy(fullname, name, EXR_PASS_MAXNAME);
+ if (view && view[0]) {
+ strncat(fullname, ".", EXR_PASS_MAXNAME);
+ strncat(fullname, view, EXR_PASS_MAXNAME);
}
- else {
- BLI_snprintf(passname, EXR_PASS_MAXNAME, "%s.%s", passtype_name, view);
+ if (channel >= 0) {
+ char token[3] = {'.', chan_id[channel], '\0'};
+ strncat(fullname, token, EXR_PASS_MAXNAME);
}
}
/********************************** New **************************************/
-static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
+static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, const char *name, const char *viewname, const char *chan_id)
{
const int view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name));
- const char *typestr = name_from_passtype(passtype, -1);
- RenderPass *rpass = MEM_callocN(sizeof(RenderPass), typestr);
+ RenderPass *rpass = MEM_callocN(sizeof(RenderPass), name);
size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels;
- rpass->passtype = passtype;
rpass->channels = channels;
rpass->rectx = rl->rectx;
rpass->recty = rl->recty;
rpass->view_id = view_id;
- set_pass_name(rpass->name, rpass->passtype, -1, viewname);
- BLI_strncpy(rpass->internal_name, typestr, sizeof(rpass->internal_name));
+ BLI_strncpy(rpass->name, name, sizeof(rpass->name));
+ BLI_strncpy(rpass->chan_id, chan_id, sizeof(rpass->chan_id));
BLI_strncpy(rpass->view, viewname, sizeof(rpass->view));
+ set_pass_full_name(rpass->fullname, rpass->name, -1, rpass->view, rpass->chan_id);
if (rl->exrhandle) {
int a;
- for (a = 0; a < channels; a++)
- IMB_exr_add_channel(rl->exrhandle, rl->name, name_from_passtype(passtype, a), viewname, 0, 0, NULL, false);
+ for (a = 0; a < channels; a++) {
+ char passname[EXR_PASS_MAXNAME];
+ IMB_exr_add_channel(rl->exrhandle, rl->name, set_pass_name(passname, rpass->name, a, rpass->chan_id), viewname, 0, 0, NULL, false);
+ }
}
else {
float *rect;
int x;
- rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, typestr);
+ rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, name);
if (rpass->rect == NULL) {
MEM_freeN(rpass);
return NULL;
}
- if (passtype == SCE_PASS_VECTOR) {
+ if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
/* initialize to max speed */
rect = rpass->rect;
for (x = rectsize - 1; x >= 0; x--)
rect[x] = PASS_VECTOR_MAX;
}
- else if (passtype == SCE_PASS_Z) {
+ else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
rect = rpass->rect;
for (x = rectsize - 1; x >= 0; x--)
rect[x] = 10e10;
@@ -541,56 +250,10 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int
return rpass;
}
/* wrapper called from render_opengl */
-RenderPass *gp_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
-{
- return render_layer_add_pass(rr, rl, channels, passtype, viewname);
-}
-
-#ifdef WITH_CYCLES_DEBUG
-const char *RE_debug_pass_name_get(int debug_type)
-{
- switch (debug_type) {
- case RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS:
- return "BVH Traversal Steps";
- case RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES:
- return "BVH Traversed Instances";
- case RENDER_PASS_DEBUG_RAY_BOUNCES:
- return "Ray Bounces";
- }
- return "Unknown";
-}
-
-int RE_debug_pass_num_channels_get(int UNUSED(debug_type))
-{
- /* Only single case currently, might be handy for further debug passes. */
- return 1;
-}
-
-static RenderPass *render_layer_add_debug_pass(RenderResult *rr,
- RenderLayer *rl,
- int pass_type,
- int debug_type,
- const char *view)
-{
- const char *name = RE_debug_pass_name_get(debug_type);
- int channels = RE_debug_pass_num_channels_get(debug_type);
- RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type, view);
- if (rpass == NULL) {
- return NULL;
- }
- rpass->debug_type = debug_type;
- BLI_strncpy(rpass->name,
- name,
- sizeof(rpass->name));
- BLI_strncpy(rpass->internal_name, rpass->name, sizeof(rpass->internal_name));
- return rpass;
-}
-
-int RE_debug_pass_type_get(Render *re)
+RenderPass *gp_add_pass(RenderResult *rr, RenderLayer *rl, int channels, const char *name, const char *viewname)
{
- return re->r.debug_pass_type;
+ return render_layer_add_pass(rr, rl, channels, name, viewname, "RGBA");
}
-#endif
/* called by main render as well for parts */
/* will read info from Render *re to define layers */
@@ -681,89 +344,77 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
if (rr->do_exr_tile)
IMB_exr_add_view(rl->exrhandle, view);
-#define RENDER_LAYER_ADD_PASS_SAFE(rr, rl, channels, passtype, viewname) \
+#define RENDER_LAYER_ADD_PASS_SAFE(rr, rl, channels, name, viewname, chan_id) \
do { \
- if (render_layer_add_pass(rr, rl, channels, passtype, viewname) == NULL) { \
+ if (render_layer_add_pass(rr, rl, channels, name, viewname, chan_id) == NULL) { \
render_result_free(rr); \
return NULL; \
} \
} while (false)
/* a renderlayer should always have a Combined pass*/
- render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view);
+ render_layer_add_pass(rr, rl, 4, "Combined", view, "RGBA");
if (srl->passflag & SCE_PASS_Z)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_Z, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_Z, view, "Z");
if (srl->passflag & SCE_PASS_VECTOR)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, SCE_PASS_VECTOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_VECTOR, view, "XYZW");
if (srl->passflag & SCE_PASS_NORMAL)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_NORMAL, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_NORMAL, view, "XYZ");
if (srl->passflag & SCE_PASS_UV)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_UV, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_UV, view, "UVA");
if (srl->passflag & SCE_PASS_RGBA)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, SCE_PASS_RGBA, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_RGBA, view, "RGBA");
if (srl->passflag & SCE_PASS_EMIT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_EMIT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_EMIT, view, "RGB");
if (srl->passflag & SCE_PASS_DIFFUSE)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE, view, "RGB");
if (srl->passflag & SCE_PASS_SPEC)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SPEC, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SPEC, view, "RGB");
if (srl->passflag & SCE_PASS_AO)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_AO, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_AO, view, "RGB");
if (srl->passflag & SCE_PASS_ENVIRONMENT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_ENVIRONMENT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_ENVIRONMENT, view, "RGB");
if (srl->passflag & SCE_PASS_INDIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_INDIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_SHADOW)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SHADOW, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SHADOW, view, "RGB");
if (srl->passflag & SCE_PASS_REFLECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_REFLECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_REFLECT, view, "RGB");
if (srl->passflag & SCE_PASS_REFRACT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_REFRACT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_REFRACT, view, "RGB");
if (srl->passflag & SCE_PASS_INDEXOB)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_INDEXOB, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXOB, view, "X");
if (srl->passflag & SCE_PASS_INDEXMA)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_INDEXMA, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXMA, view, "X");
if (srl->passflag & SCE_PASS_MIST)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_MIST, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_MIST, view, "Z");
if (rl->passflag & SCE_PASS_RAYHITS)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, SCE_PASS_RAYHITS, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_RAYHITS, view, "RGB");
if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_DIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_INDIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_DIFFUSE_COLOR)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_COLOR, view, "RGB");
if (srl->passflag & SCE_PASS_GLOSSY_DIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_DIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_INDIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_GLOSSY_COLOR)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_COLOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_COLOR, view, "RGB");
if (srl->passflag & SCE_PASS_TRANSM_DIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_DIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_TRANSM_INDIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_INDIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_TRANSM_COLOR)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_COLOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_COLOR, view, "RGB");
if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_DIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_INDIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR, view);
-
-#ifdef WITH_CYCLES_DEBUG
- if (BKE_scene_use_new_shading_nodes(re->scene)) {
- if (render_layer_add_debug_pass(rr, rl, SCE_PASS_DEBUG,
- re->r.debug_pass_type, view) == NULL)
- {
- render_result_free(rr);
- return NULL;
- }
- }
-#endif
-
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_COLOR, view, "RGB");
#undef RENDER_LAYER_ADD_PASS_SAFE
}
}
@@ -792,7 +443,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
IMB_exr_add_view(rl->exrhandle, view);
/* a renderlayer should always have a Combined pass */
- render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view);
+ render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, view, "RGBA");
}
/* note, this has to be in sync with scene.c */
@@ -811,6 +462,60 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
return rr;
}
+void render_result_clone_passes(Render *re, RenderResult *rr, const char *viewname)
+{
+ RenderLayer *rl;
+ RenderPass *main_rp;
+
+ for (rl = rr->layers.first; rl; rl = rl->next) {
+ RenderLayer *main_rl = BLI_findstring(&re->result->layers, rl->name, offsetof(RenderLayer, name));
+ if (!main_rl) {
+ continue;
+ }
+
+ for (main_rp = main_rl->passes.first; main_rp; main_rp = main_rp->next) {
+ if (viewname && viewname[0] && !STREQ(main_rp->view, viewname)) {
+ continue;
+ }
+
+ /* Compare fullname to make sure that the view also is equal. */
+ RenderPass *rp = BLI_findstring(&rl->passes, main_rp->fullname, offsetof(RenderPass, fullname));
+ if (!rp) {
+ render_layer_add_pass(rr, rl, main_rp->channels, main_rp->name, main_rp->view, main_rp->chan_id);
+ }
+ }
+ }
+}
+
+void render_result_add_pass(RenderResult *rr, const char *name, int channels, const char *chan_id, const char *layername, const char *viewname)
+{
+ RenderLayer *rl;
+ RenderPass *rp;
+ RenderView *rv;
+
+ for (rl = rr->layers.first; rl; rl = rl->next) {
+ if (layername && layername[0] && !STREQ(rl->name, layername)) {
+ continue;
+ }
+
+ for (rv = rr->views.first; rv; rv = rv->next) {
+ const char *view = rv->name;
+
+ if (viewname && viewname[0] && !STREQ(view, viewname)) continue;
+
+ /* Ensure that the pass doesn't exist yet. */
+ for (rp = rl->passes.first; rp; rp = rp->next) {
+ if (!STREQ(rp->name, name)) continue;
+ if (!STREQ(rp->view, view)) continue;
+ }
+
+ if (!rp) {
+ render_layer_add_pass(rr, rl, channels, name, view, chan_id);
+ }
+ }
+ }
+}
+
/* allocate osa new results for samples */
RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers, const char *viewname)
{
@@ -828,6 +533,50 @@ RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *part
return lb->first;
}
+static int passtype_from_name(const char *name)
+{
+ const char delim[] = {'.', '\0'};
+ const char *sep, *suf;
+ int len = BLI_str_partition(name, delim, &sep, &suf);
+
+#define CHECK_PASS(NAME) if (STREQLEN(name, RE_PASSNAME_ ## NAME, len)) return SCE_PASS_ ## NAME
+
+ CHECK_PASS(COMBINED);
+ CHECK_PASS(Z);
+ CHECK_PASS(VECTOR);
+ CHECK_PASS(NORMAL);
+ CHECK_PASS(UV);
+ CHECK_PASS(RGBA);
+ CHECK_PASS(EMIT);
+ CHECK_PASS(DIFFUSE);
+ CHECK_PASS(SPEC);
+ CHECK_PASS(SHADOW);
+ CHECK_PASS(AO);
+ CHECK_PASS(ENVIRONMENT);
+ CHECK_PASS(INDIRECT);
+ CHECK_PASS(REFLECT);
+ CHECK_PASS(REFRACT);
+ CHECK_PASS(INDEXOB);
+ CHECK_PASS(INDEXMA);
+ CHECK_PASS(MIST);
+ CHECK_PASS(RAYHITS);
+ CHECK_PASS(DIFFUSE_DIRECT);
+ CHECK_PASS(DIFFUSE_INDIRECT);
+ CHECK_PASS(DIFFUSE_COLOR);
+ CHECK_PASS(GLOSSY_DIRECT);
+ CHECK_PASS(GLOSSY_INDIRECT);
+ CHECK_PASS(GLOSSY_COLOR);
+ CHECK_PASS(TRANSM_DIRECT);
+ CHECK_PASS(TRANSM_INDIRECT);
+ CHECK_PASS(TRANSM_COLOR);
+ CHECK_PASS(SUBSURFACE_DIRECT);
+ CHECK_PASS(SUBSURFACE_INDIRECT);
+ CHECK_PASS(SUBSURFACE_COLOR);
+
+#undef CHECK_PASS
+ return 0;
+}
+
/* callbacks for render_result_new_from_exr */
static void *ml_addlayer_cb(void *base, const char *str)
{
@@ -841,36 +590,30 @@ static void *ml_addlayer_cb(void *base, const char *str)
return rl;
}
-static void ml_addpass_cb(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id, const char *view)
+static void ml_addpass_cb(void *base, void *lay, const char *name, float *rect, int totchan, const char *chan_id, const char *view)
{
RenderResult *rr = base;
RenderLayer *rl = lay;
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), "loaded pass");
- int a;
-
+
BLI_addtail(&rl->passes, rpass);
rpass->channels = totchan;
- rpass->passtype = passtype_from_name(str, rl->passflag);
- if (rpass->passtype == 0)
- printf("unknown pass %s\n", str);
- rl->passflag |= rpass->passtype;
-
+ rl->passflag |= passtype_from_name(name);
+
/* channel id chars */
- for (a = 0; a < totchan; a++)
- rpass->chan_id[a] = chan_id[a];
+ BLI_strncpy(rpass->chan_id, chan_id, sizeof(rpass->chan_id));
rpass->rect = rect;
+ BLI_strncpy(rpass->name, name, EXR_PASS_MAXNAME);
+ BLI_strncpy(rpass->view, view, sizeof(rpass->view));
+ set_pass_full_name(rpass->fullname, name, -1, view, rpass->chan_id);
+
if (view[0] != '\0') {
- BLI_snprintf(rpass->name, sizeof(rpass->name), "%s.%s", str, view);
rpass->view_id = BLI_findstringindex(&rr->views, view, offsetof(RenderView, name));
}
else {
- BLI_strncpy(rpass->name, str, sizeof(rpass->name));
rpass->view_id = 0;
}
-
- BLI_strncpy(rpass->view, view, sizeof(rpass->view));
- BLI_strncpy(rpass->internal_name, str, sizeof(rpass->internal_name));
}
static void *ml_addview_cb(void *base, const char *str)
@@ -910,12 +653,30 @@ static int order_render_passes(const void *a, const void *b)
// 1 if a is after b
RenderPass *rpa = (RenderPass *) a;
RenderPass *rpb = (RenderPass *) b;
+ unsigned int passtype_a = passtype_from_name(rpa->name);
+ unsigned int passtype_b = passtype_from_name(rpb->name);
- if (rpa->passtype > rpb->passtype)
+ /* Render passes with default type always go first. */
+ if (passtype_b && !passtype_a)
return 1;
- else if (rpa->passtype < rpb->passtype)
+ if (passtype_a && !passtype_b)
return 0;
+ if (passtype_a && passtype_b) {
+ if (passtype_a > passtype_b)
+ return 1;
+ else if (passtype_a < passtype_b)
+ return 0;
+ }
+ else {
+ int cmp = strncmp(rpa->name, rpb->name, EXR_PASS_MAXNAME);
+ if (cmp > 0)
+ return 1;
+ if (cmp < 0)
+ return 0;
+ }
+
+
/* they have the same type */
/* left first */
if (STREQ(rpa->view, STEREO_LEFT_NAME))
@@ -1047,7 +808,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
rpass = rpass->next)
{
/* renderresult have all passes, renderpart only the active view's passes */
- if (strcmp(rpassp->name, rpass->name) != 0)
+ if (strcmp(rpassp->fullname, rpass->fullname) != 0)
continue;
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
@@ -1059,21 +820,6 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
}
}
-/* for passes read from files, these have names stored */
-static char *make_pass_name(RenderPass *rpass, int chan)
-{
- static char name[EXR_PASS_MAXNAME];
- int len;
-
- BLI_strncpy(name, rpass->name, EXR_PASS_MAXNAME);
- len = strlen(name);
- name[len] = '.';
- name[len + 1] = rpass->chan_id[chan];
- name[len + 2] = 0;
-
- return name;
-}
-
/* called from within UI and render pipeline, saves both rendered result as a file-read result
* if multiview is true saves all views in a multiview exr
* else if view is not NULL saves single view
@@ -1134,8 +880,10 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil
IMB_exr_add_view(exrhandle, rview->name);
if (rview->rectf) {
+ char passname[EXR_PASS_MAXNAME];
for (a = 0; a < 4; a++) {
- IMB_exr_add_channel(exrhandle, "Composite", name_from_passtype(SCE_PASS_COMBINED, a),
+ set_pass_name(passname, RE_PASSNAME_COMBINED, a, "RGBA");
+ IMB_exr_add_channel(exrhandle, RE_PASSNAME_COMBINED, passname,
chan_view, 4, 4 * width, rview->rectf + a,
use_half_float);
}
@@ -1148,6 +896,7 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil
/* passes are allocated in sync */
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
const int xstride = rpass->channels;
+ char passname[EXR_PASS_MAXNAME];
if (is_mono) {
if (!STREQ(view, rpass->view)) {
@@ -1161,16 +910,10 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil
}
for (a = 0; a < xstride; a++) {
- if (rpass->passtype) {
- IMB_exr_add_channel(exrhandle, rl->name, name_from_passtype(rpass->passtype, a), chan_view,
- xstride, xstride * width, rpass->rect + a,
- rpass->passtype == SCE_PASS_Z ? false : use_half_float);
- }
- else {
- IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), chan_view,
- xstride, xstride * width, rpass->rect + a,
- use_half_float);
- }
+ set_pass_name(passname, rpass->name, a, rpass->chan_id);
+ IMB_exr_add_channel(exrhandle, rl->name, passname, chan_view,
+ xstride, xstride * width, rpass->rect + a,
+ STREQ(rpass->name, RE_PASSNAME_Z) ? false : use_half_float);
}
}
}
@@ -1279,12 +1022,12 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons
for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) {
const int xstride = rpassp->channels;
int a;
- char passname[EXR_PASS_MAXNAME];
+ char fullname[EXR_PASS_MAXNAME];
for (a = 0; a < xstride; a++) {
- set_pass_name(passname, rpassp->passtype, a, rpassp->view);
+ set_pass_full_name(fullname, rpassp->name, a, viewname, rpassp->chan_id);
- IMB_exr_set_channel(rl->exrhandle, rlp->name, passname,
+ IMB_exr_set_channel(rl->exrhandle, rlp->name, fullname,
xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs);
}
}
@@ -1447,15 +1190,15 @@ int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, c
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
const int xstride = rpass->channels;
int a;
- char passname[EXR_PASS_MAXNAME];
+ char fullname[EXR_PASS_MAXNAME];
for (a = 0; a < xstride; a++) {
- set_pass_name(passname, rpass->passtype, a, rpass->view);
- IMB_exr_set_channel(exrhandle, rl->name, passname,
+ set_pass_full_name(fullname, rpass->name, a, rpass->view, rpass->chan_id);
+ IMB_exr_set_channel(exrhandle, rl->name, fullname,
xstride, xstride * rectx, rpass->rect + a);
}
- set_pass_name(rpass->name, rpass->passtype, -1, rpass->view);
+ set_pass_full_name(rpass->fullname, rpass->name, -1, rpass->view, rpass->chan_id);
}
}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index b4a14f5337d..91d1f63a1be 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -781,7 +781,8 @@ static int cubemap_glob(const float n[3], float x, float y, float z, float *adr1
/* ------------------------------------------------------------------------- */
/* mtex argument only for projection switches */
-static int cubemap(MTex *mtex, VlakRen *vlr, const float n[3], float x, float y, float z, float *adr1, float *adr2)
+static int cubemap(
+ const MTex *mtex, VlakRen *vlr, const float n[3], float x, float y, float z, float *adr1, float *adr2)
{
int proj[4]={0, ME_PROJXY, ME_PROJXZ, ME_PROJYZ}, ret= 0;
@@ -873,7 +874,8 @@ static int cubemap_ob(Object *ob, const float n[3], float x, float y, float z, f
/* ------------------------------------------------------------------------- */
-static void do_2d_mapping(MTex *mtex, float texvec[3], VlakRen *vlr, const float n[3], float dxt[3], float dyt[3])
+static void do_2d_mapping(
+ const MTex *mtex, float texvec[3], VlakRen *vlr, const float n[3], float dxt[3], float dyt[3])
{
Tex *tex;
Object *ob= NULL;
@@ -1112,14 +1114,15 @@ static int multitex(Tex *tex,
const short which_output,
struct ImagePool *pool,
const bool skip_load_image,
- const bool texnode_preview)
+ const bool texnode_preview,
+ const bool use_nodes)
{
float tmpvec[3];
int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */
texres->talpha = false; /* is set when image texture returns alpha (considered premul) */
- if (tex->use_nodes && tex->nodetree) {
+ if (use_nodes && tex->use_nodes && tex->nodetree) {
retval = ntreeTexExecTree(tex->nodetree, texres, texvec, dxt, dyt, osatex, thread,
tex, which_output, R.r.cfra, texnode_preview, NULL, NULL);
}
@@ -1239,7 +1242,8 @@ static int multitex_nodes_intern(Tex *tex,
ImagePool *pool,
const bool scene_color_manage,
const bool skip_load_image,
- const bool texnode_preview)
+ const bool texnode_preview,
+ const bool use_nodes)
{
if (tex==NULL) {
memset(texres, 0, sizeof(TexResult));
@@ -1264,7 +1268,8 @@ static int multitex_nodes_intern(Tex *tex,
which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ use_nodes);
if (mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) {
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
@@ -1311,7 +1316,8 @@ static int multitex_nodes_intern(Tex *tex,
which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ use_nodes);
{
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
@@ -1341,7 +1347,8 @@ static int multitex_nodes_intern(Tex *tex,
which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ use_nodes);
}
}
@@ -1354,7 +1361,8 @@ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int os
return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres,
thread, which_output, shi, mtex, pool, R.scene_color_manage,
(R.r.scemode & R_NO_IMAGE_LOAD) != 0,
- (R.r.scemode & R_TEXNODE_PREVIEW) != 0);
+ (R.r.scemode & R_TEXNODE_PREVIEW) != 0,
+ true);
}
/* this is called for surface shading */
@@ -1378,7 +1386,8 @@ static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt
mtex->which_output,
pool,
skip_load_image,
- (R.r.scemode & R_TEXNODE_PREVIEW) != 0);
+ (R.r.scemode & R_TEXNODE_PREVIEW) != 0,
+ true);
}
}
@@ -1408,7 +1417,8 @@ int multitex_ext(Tex *tex,
pool,
scene_color_manage,
skip_load_image,
- false);
+ false,
+ true);
}
/* extern-tex doesn't support nodes (ntreeBeginExec() can't be called when rendering is going on)\
@@ -1417,13 +1427,19 @@ int multitex_ext(Tex *tex,
*/
int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image)
{
- int use_nodes= tex->use_nodes, retval;
-
- tex->use_nodes = false;
- retval= multitex_nodes_intern(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL, pool, scene_color_manage, skip_load_image, false);
- tex->use_nodes= use_nodes;
-
- return retval;
+ return multitex_nodes_intern(tex,
+ texvec,
+ NULL, NULL,
+ 0,
+ texres,
+ 0,
+ 0,
+ NULL, NULL,
+ pool,
+ scene_color_manage,
+ skip_load_image,
+ false,
+ false);
}
@@ -1481,6 +1497,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa
case MTEX_SUB:
fact= -fact;
+ ATTR_FALLTHROUGH;
case MTEX_ADD:
fact*= facg;
in[0]= (fact*tex[0] + out[0]);
@@ -1595,6 +1612,7 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
case MTEX_SUB:
fact= -fact;
+ ATTR_FALLTHROUGH;
case MTEX_ADD:
in= fact*tex + out;
break;
@@ -2873,7 +2891,8 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
mtex->which_output,
re->pool,
skip_load_image,
- texnode_preview); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
+ texnode_preview,
+ true); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
/* texture output */
@@ -3051,7 +3070,8 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
mtex->which_output,
har->pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3274,7 +3294,8 @@ void do_sky_tex(
mtex->which_output,
R.pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3500,7 +3521,8 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r
mtex->which_output,
R.pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3574,7 +3596,7 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r
/* ------------------------------------------------------------------------- */
-int externtex(MTex *mtex,
+int externtex(const MTex *mtex,
const float vec[3],
float *tin, float *tr, float *tg, float *tb, float *ta,
const int thread,
@@ -3614,7 +3636,8 @@ int externtex(MTex *mtex,
mtex->which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
if (rgb) {
texr.tin = IMB_colormanagement_get_luminance(&texr.tr);
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index 910ea16607e..77f399d08d1 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -180,11 +180,12 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
flarec= 0;
if (fullsample) {
- for (sample=0; sample<totsample; sample++)
+ for (sample=0; sample<totsample; sample++) {
if (ps->mask & (1 << sample)) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
addalphaAddfacFloat(pass + od*4, col, har->add);
}
+ }
}
else {
fac= ((float)amountm)/(float)R.osa;
@@ -215,11 +216,12 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
}
if (fullsample) {
- for (sample=0; sample<totsample; sample++)
+ for (sample=0; sample<totsample; sample++) {
if (!(mask & (1 << sample))) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
addalphaAddfacFloat(pass + od*4, col, har->add);
}
+ }
}
else {
col[0]= accol[0];
@@ -228,7 +230,7 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
col[3]= accol[3];
for (sample=0; sample<totsample; sample++) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
addalphaAddfacFloat(pass + od*4, col, har->add);
}
}
@@ -312,7 +314,7 @@ static void halo_tile(RenderPart *pa, RenderLayer *rl)
if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) {
if (shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec)) {
for (sample=0; sample<totsample; sample++) {
- float * rect= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ float * rect= RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
addalphaAddfacFloat(rect + od*4, col, har->add);
}
}
@@ -367,7 +369,7 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
if (fullsample) {
for (sample=0; sample<totsample; sample++) {
if (ps->mask & (1 << sample)) {
- pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
@@ -379,7 +381,7 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
}
else {
fac= ((float)count)/(float)R.osa;
- pass = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
pass += od * 4;
pass[0]+= fac*col[0];
pass[1]+= fac*col[1];
@@ -401,7 +403,7 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
for (sample=0; sample<totsample; sample++) {
if (!(mask & (1 << sample))) {
- pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
@@ -413,7 +415,7 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
}
else {
fac= ((float)R.osa-totsamp)/(float)R.osa;
- pass = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
pass += od * 4;
pass[0]+= fac*col[0];
pass[1]+= fac*col[1];
@@ -433,7 +435,7 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
renderspothalo(&shi, col, 1.0f);
for (sample=0; sample<totsample; sample++) {
- pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
@@ -462,101 +464,96 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset,
float *fp, *col= NULL;
int pixsize= 3;
- switch (rpass->passtype) {
- case SCE_PASS_COMBINED:
- add_filt_fmask(curmask, shr->combined, rpass->rect + 4*offset, rectx);
- break;
- case SCE_PASS_Z:
- fp= rpass->rect + offset;
- *fp= shr->z;
- break;
- case SCE_PASS_RGBA:
- col= shr->col;
- pixsize= 4;
- break;
- case SCE_PASS_EMIT:
- col= shr->emit;
- break;
- case SCE_PASS_DIFFUSE:
- col= shr->diff;
- break;
- case SCE_PASS_SPEC:
- col= shr->spec;
- break;
- case SCE_PASS_SHADOW:
- col= shr->shad;
- break;
- case SCE_PASS_AO:
- col= shr->ao;
- break;
- case SCE_PASS_ENVIRONMENT:
- col= shr->env;
- break;
- case SCE_PASS_INDIRECT:
- col= shr->indirect;
- break;
- case SCE_PASS_REFLECT:
- col= shr->refl;
- break;
- case SCE_PASS_REFRACT:
- col= shr->refr;
- break;
- case SCE_PASS_NORMAL:
- col= shr->nor;
- break;
- case SCE_PASS_UV:
- /* box filter only, gauss will screwup UV too much */
- if (shi->totuv) {
- float mult= (float)count_mask(curmask)/(float)R.osa;
- fp= rpass->rect + 3*offset;
- fp[0]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[0]);
- fp[1]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[1]);
- fp[2]+= mult;
- }
- break;
- case SCE_PASS_INDEXOB:
- /* no filter */
- if (shi->vlr) {
- fp= rpass->rect + offset;
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
+ add_filt_fmask(curmask, shr->combined, rpass->rect + 4*offset, rectx);
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
+ fp = rpass->rect + offset;
+ *fp = shr->z;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
+ col = shr->col;
+ pixsize = 4;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
+ col = shr->emit;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
+ col = shr->diff;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
+ col = shr->spec;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
+ col = shr->shad;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
+ col = shr->ao;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
+ col = shr->env;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
+ col = shr->indirect;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
+ col = shr->refl;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
+ col = shr->refr;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
+ col = shr->nor;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_UV)) {
+ /* box filter only, gauss will screwup UV too much */
+ if (shi->totuv) {
+ float mult = (float)count_mask(curmask)/(float)R.osa;
+ fp = rpass->rect + 3*offset;
+ fp[0]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[0]);
+ fp[1]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[1]);
+ fp[2]+= mult;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
+ /* no filter */
+ if (shi->vlr) {
+ fp = rpass->rect + offset;
+ if (*fp==0.0f)
+ *fp = (float)shi->obr->ob->index;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
+ /* no filter */
+ if (shi->vlr) {
+ fp = rpass->rect + offset;
if (*fp==0.0f)
- *fp= (float)shi->obr->ob->index;
- }
- break;
- case SCE_PASS_INDEXMA:
- /* no filter */
- if (shi->vlr) {
- fp= rpass->rect + offset;
- if (*fp==0.0f)
- *fp= (float)shi->mat->index;
- }
- break;
- case SCE_PASS_MIST:
- /* */
- col= &shr->mist;
- pixsize= 1;
- break;
-
- case SCE_PASS_VECTOR:
- {
- /* add minimum speed in pixel, no filter */
- fp= rpass->rect + 4*offset;
- if ( (ABS(shr->winspeed[0]) + ABS(shr->winspeed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
- fp[0]= shr->winspeed[0];
- fp[1]= shr->winspeed[1];
- }
- if ( (ABS(shr->winspeed[2]) + ABS(shr->winspeed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
- fp[2]= shr->winspeed[2];
- fp[3]= shr->winspeed[3];
- }
-
- break;
+ *fp = (float)shi->mat->index;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
+ /* */
+ col = &shr->mist;
+ pixsize = 1;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
+ /* add minimum speed in pixel, no filter */
+ fp = rpass->rect + 4*offset;
+ if ( (ABS(shr->winspeed[0]) + ABS(shr->winspeed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
+ fp[0] = shr->winspeed[0];
+ fp[1] = shr->winspeed[1];
+ }
+ if ( (ABS(shr->winspeed[2]) + ABS(shr->winspeed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
+ fp[2] = shr->winspeed[2];
+ fp[3] = shr->winspeed[3];
}
- case SCE_PASS_RAYHITS:
- /* */
- col= shr->rayhits;
- pixsize= 4;
- break;
}
+ else if (STREQ(rpass->name, RE_PASSNAME_RAYHITS)) {
+ /* */
+ col = shr->rayhits;
+ pixsize= 4;
+ }
+
if (col) {
fp= rpass->rect + pixsize*offset;
add_filt_fmask_pixsize(curmask, col, fp, rectx, pixsize);
@@ -574,86 +571,85 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult
float *col= NULL, uvcol[3];
int a, pixsize= 3;
- switch (rpass->passtype) {
- case SCE_PASS_COMBINED:
- /* copy combined to use for preview */
- copy_v4_v4(rpass->rect + 4*offset, shr->combined);
- break;
- case SCE_PASS_Z:
- fp= rpass->rect + offset;
- *fp= shr->z;
- break;
- case SCE_PASS_RGBA:
- col= shr->col;
- pixsize= 4;
- break;
- case SCE_PASS_EMIT:
- col= shr->emit;
- break;
- case SCE_PASS_DIFFUSE:
- col= shr->diff;
- break;
- case SCE_PASS_SPEC:
- col= shr->spec;
- break;
- case SCE_PASS_SHADOW:
- col= shr->shad;
- break;
- case SCE_PASS_AO:
- col= shr->ao;
- break;
- case SCE_PASS_ENVIRONMENT:
- col= shr->env;
- break;
- case SCE_PASS_INDIRECT:
- col= shr->indirect;
- break;
- case SCE_PASS_REFLECT:
- col= shr->refl;
- break;
- case SCE_PASS_REFRACT:
- col= shr->refr;
- break;
- case SCE_PASS_NORMAL:
- col= shr->nor;
- break;
- case SCE_PASS_UV:
- if (shi->totuv) {
- uvcol[0]= 0.5f + 0.5f*shi->uv[shi->actuv].uv[0];
- uvcol[1]= 0.5f + 0.5f*shi->uv[shi->actuv].uv[1];
- uvcol[2]= 1.0f;
- col= uvcol;
- }
- break;
- case SCE_PASS_VECTOR:
- col= shr->winspeed;
- pixsize= 4;
- break;
- case SCE_PASS_INDEXOB:
- if (shi->vlr) {
- fp= rpass->rect + offset;
- *fp= (float)shi->obr->ob->index;
- }
- break;
- case SCE_PASS_INDEXMA:
- if (shi->vlr) {
- fp= rpass->rect + offset;
- *fp= (float)shi->mat->index;
- }
- break;
- case SCE_PASS_MIST:
- fp= rpass->rect + offset;
- *fp= shr->mist;
- break;
- case SCE_PASS_RAYHITS:
- col= shr->rayhits;
- pixsize= 4;
- break;
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
+ /* copy combined to use for preview */
+ copy_v4_v4(rpass->rect + 4*offset, shr->combined);
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
+ fp = rpass->rect + offset;
+ *fp = shr->z;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
+ col = shr->col;
+ pixsize = 4;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
+ col = shr->emit;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
+ col = shr->diff;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
+ col = shr->spec;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
+ col = shr->shad;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
+ col = shr->ao;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
+ col = shr->env;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
+ col = shr->indirect;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
+ col = shr->refl;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
+ col = shr->refr;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
+ col = shr->nor;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_UV)) {
+ if (shi->totuv) {
+ uvcol[0] = 0.5f + 0.5f*shi->uv[shi->actuv].uv[0];
+ uvcol[1] = 0.5f + 0.5f*shi->uv[shi->actuv].uv[1];
+ uvcol[2] = 1.0f;
+ col = uvcol;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
+ col = shr->winspeed;
+ pixsize = 4;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
+ if (shi->vlr) {
+ fp = rpass->rect + offset;
+ *fp = (float)shi->obr->ob->index;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
+ if (shi->vlr) {
+ fp = rpass->rect + offset;
+ *fp = (float)shi->mat->index;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
+ fp = rpass->rect + offset;
+ *fp = shr->mist;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_RAYHITS)) {
+ col = shr->rayhits;
+ pixsize = 4;
}
+
if (col) {
- fp= rpass->rect + pixsize*offset;
+ fp = rpass->rect + pixsize*offset;
for (a=0; a<pixsize; a++)
- fp[a]= col[a];
+ fp[a] = col[a];
}
}
}
@@ -696,7 +692,7 @@ static void sky_tile(RenderPart *pa, RenderLayer *rl)
bool done = false;
for (sample= 0; sample<totsample; sample++) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
pass += od;
if (pass[3]<1.0f) {
@@ -737,7 +733,7 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl)
/* check that z pass is enabled */
if (pa->rectz==NULL) return;
for (zpass= rl->passes.first; zpass; zpass= zpass->next)
- if (zpass->passtype==SCE_PASS_Z)
+ if (STREQ(zpass->name, RE_PASSNAME_Z))
break;
if (zpass==NULL) return;
@@ -758,8 +754,8 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl)
int sample;
for (sample=0; sample<totsample; sample++) {
- const float *zrect = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_Z, R.viewname) + od;
- float *rgbrect = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname) + 4*od;
+ const float *zrect = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_Z, R.viewname) + od;
+ float *rgbrect = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname) + 4*od;
float rgb[3] = {0};
bool done = false;
@@ -994,7 +990,7 @@ static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl)
return;
for (sample= 0; sample<totsample; sample++) {
- float *rectf = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ float *rectf = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
for (y= pa->rectx*pa->recty; y>0; y--, rectf+=4) {
rectf[0] = MAX2(rectf[0], 0.0f);
@@ -1076,7 +1072,7 @@ static void reset_sky_speed(RenderPart *pa, RenderLayer *rl)
totsample= get_sample_layers(pa, rl, rlpp);
for (sample= 0; sample<totsample; sample++) {
- fp= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_VECTOR, R.viewname);
+ fp= RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_VECTOR, R.viewname);
if (fp==NULL) break;
for (a= 4*pa->rectx*pa->recty - 1; a>=0; a--)
@@ -1187,7 +1183,7 @@ void zbufshadeDA_tile(RenderPart *pa)
pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
for (rl= rr->layers.first; rl; rl= rl->next) {
- float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ float *rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
@@ -1339,7 +1335,7 @@ void zbufshade_tile(RenderPart *pa)
pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
for (rl= rr->layers.first; rl; rl= rl->next) {
- float *rect= RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ float *rect= RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
@@ -1676,7 +1672,7 @@ void zbufshade_sss_tile(RenderPart *pa)
return;
}
- fcol= RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ fcol= RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
co= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSCo");
color= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSColor");
@@ -1969,7 +1965,7 @@ void add_halo_flare(Render *re)
if ((rl->layflag & SCE_LAY_HALO) == 0)
continue;
- rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname);
+ rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, re->viewname);
if (rect==NULL)
continue;
@@ -1998,3 +1994,37 @@ void add_halo_flare(Render *re)
}
}
+void render_internal_update_passes(RenderEngine *engine, Scene *scene, SceneRenderLayer *srl)
+{
+ int type;
+
+ RE_engine_register_pass(engine, scene, srl, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA);
+
+#define CHECK_PASS(name, channels, chanid) \
+ if (srl->passflag & (SCE_PASS_ ## name)) { \
+ if (channels == 4) type = SOCK_RGBA; \
+ else if (channels == 3) type = SOCK_VECTOR; \
+ else type = SOCK_FLOAT; \
+ RE_engine_register_pass(engine, scene, srl, RE_PASSNAME_ ## name, channels, chanid, type); \
+ }
+
+ CHECK_PASS(Z, 1, "Z");
+ CHECK_PASS(VECTOR, 4, "XYZW");
+ CHECK_PASS(NORMAL, 3, "XYZ");
+ CHECK_PASS(UV, 3, "UVA");
+ CHECK_PASS(RGBA, 4, "RGBA");
+ CHECK_PASS(EMIT, 3, "RGB");
+ CHECK_PASS(DIFFUSE, 3, "RGB");
+ CHECK_PASS(SPEC, 3, "RGB");
+ CHECK_PASS(AO, 3, "RGB");
+ CHECK_PASS(ENVIRONMENT, 3, "RGB");
+ CHECK_PASS(INDIRECT, 3, "RGB");
+ CHECK_PASS(SHADOW, 3, "RGB");
+ CHECK_PASS(REFLECT, 3, "RGB");
+ CHECK_PASS(REFRACT, 3, "RGB");
+ CHECK_PASS(INDEXOB, 1, "X");
+ CHECK_PASS(INDEXMA, 1, "X");
+ CHECK_PASS(MIST, 1, "Z");
+
+#undef CHECK_PASS
+}
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index 76e6ca8d467..199322795f3 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -66,6 +66,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_hash.h"
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
@@ -1458,6 +1459,14 @@ ObjectInstanceRen *RE_addRenderInstance(
}
}
+ /* Fill object info */
+ if (dob) {
+ obi->random_id = dob->random_id;
+ }
+ else {
+ obi->random_id = BLI_hash_int_2d(BLI_hash_string(obi->ob->id.name + 2), 0);
+ }
+
RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW);
if (mat) {
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index 20602314526..b4ff5f52fcf 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -292,12 +292,8 @@ void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen
}
}
-/* note, facenr declared volatile due to over-eager -O2 optimization's
- * on cygwin (particularly -frerun-cse-after-loop)
- */
-
/* copy data from face to ShadeInput, scanline case */
-void shade_input_set_triangle(ShadeInput *shi, volatile int obi, volatile int facenr, int UNUSED(normal_flip))
+void shade_input_set_triangle(ShadeInput *shi, int obi, int facenr, int UNUSED(normal_flip))
{
if (facenr > 0) {
shi->obi = &R.objectinstance[obi];
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 3d6462e09a0..8dea0930b9e 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -2141,9 +2141,19 @@ const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int m
return NULL;
}
+float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi)
+{
+ return obi->ob->index;
+}
+
+float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi)
+{
+ return obi->random_id;
+}
+
const float (*RE_render_current_get_matrix(int matrix_id))[4]
{
- switch(matrix_id) {
+ switch (matrix_id) {
case RE_VIEW_MATRIX:
return (const float(*)[4])R.viewmat;
case RE_VIEWINV_MATRIX:
@@ -2151,3 +2161,24 @@ const float (*RE_render_current_get_matrix(int matrix_id))[4]
}
return NULL;
}
+
+float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta)
+{
+ /* compute fresnel reflectance without explicitly computing
+ * the refracted direction */
+ float c = fabs(dot_v3v3(incoming, normal));
+ float g = eta * eta - 1.0 + c * c;
+ float result;
+
+ if (g > 0.0) {
+ g = sqrtf(g);
+ float A = (g - c) / (g + c);
+ float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
+ result = 0.5 * A * A * (1.0 + B * B);
+ }
+ else {
+ result = 1.0; /* TIR (no refracted component) */
+ }
+
+ return result;
+}
diff --git a/source/blender/render/intern/source/sunsky.c b/source/blender/render/intern/source/sunsky.c
index d4e53eb7305..f0cf29e98ca 100644
--- a/source/blender/render/intern/source/sunsky.c
+++ b/source/blender/render/intern/source/sunsky.c
@@ -398,7 +398,7 @@ void InitAtmosphere(struct SunSky *sunSky, float sun_intens, float mief, float r
vLambda2[0] = fLambda2[0];
vLambda2[1] = fLambda2[1];
vLambda2[2] = fLambda2[2];
-
+
vLambda4[0] = fLambda4[0];
vLambda4[1] = fLambda4[1];
vLambda4[2] = fLambda4[2];
diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c
index 5377d0eba00..752a9df0b79 100644
--- a/source/blender/render/intern/source/volume_precache.c
+++ b/source/blender/render/intern/source/volume_precache.c
@@ -60,6 +60,8 @@
#include "volumetric.h"
#include "volume_precache.h"
+#include "atomic_ops.h"
+
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
@@ -509,7 +511,8 @@ static void *vol_precache_part_test(void *data)
*/
typedef struct VolPrecacheState {
double lasttime;
- int totparts;
+ unsigned int doneparts;
+ unsigned int totparts;
} VolPrecacheState;
static void vol_precache_part(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
@@ -574,13 +577,15 @@ static void vol_precache_part(TaskPool * __restrict pool, void *taskdata, int UN
}
}
+ unsigned int doneparts = atomic_add_and_fetch_u(&state->doneparts, 1);
+
time = PIL_check_seconds_timer();
if (time - state->lasttime > 1.0) {
ThreadMutex *mutex = BLI_task_pool_user_mutex(pool);
if (BLI_mutex_trylock(mutex)) {
char str[64];
- float ratio = (float)BLI_task_pool_tasks_done(pool)/(float)state->totparts;
+ float ratio = (float)doneparts/(float)state->totparts;
BLI_snprintf(str, sizeof(str), IFACE_("Precaching volume: %d%%"), (int)(100.0f * ratio));
re->i.infostr = str;
re->stats_draw(re->sdh, &re->i);
@@ -631,6 +636,7 @@ static void precache_launch_parts(Render *re, RayObject *tree, ShadeInput *shi,
/* setup task scheduler */
memset(&state, 0, sizeof(state));
+ state.doneparts = 0;
state.totparts = parts[0]*parts[1]*parts[2];
state.lasttime = PIL_check_seconds_timer();
diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c
index 610e86caa13..7fe52328781 100644
--- a/source/blender/render/intern/source/volumetric.c
+++ b/source/blender/render/intern/source/volumetric.c
@@ -275,10 +275,12 @@ static float metadensity(Object *ob, const float co[3])
break;
case MB_CUBE:
tp[2] = (tp[2] > ml->expz) ? (tp[2] - ml->expz) : ((tp[2] < -ml->expz) ? (tp[2] + ml->expz) : 0.f);
- /* no break, xy as plane */
+ /* no break, xy as plane */
+ ATTR_FALLTHROUGH;
case MB_PLANE:
tp[1] = (tp[1] > ml->expy) ? (tp[1] - ml->expy) : ((tp[1] < -ml->expy) ? (tp[1] + ml->expy) : 0.f);
- /* no break, x as tube */
+ /* no break, x as tube */
+ ATTR_FALLTHROUGH;
case MB_TUBE:
tp[0] = (tp[0] > ml->expx) ? (tp[0] - ml->expx) : ((tp[0] < -ml->expx) ? (tp[0] + ml->expx) : 0.f);
}
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 9f777631e52..1481e7a8059 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -393,7 +393,7 @@ static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr,
zverg-= zspan->polygon_offset;
while (x>=0) {
- intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX);
+ intzverg = round_db_to_int_clamp(zverg);
if ( intzverg < *rz) {
if (!zspan->rectmask || intzverg > *rm) {
@@ -1137,7 +1137,7 @@ static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr,
x= sn2-sn1;
while (x>=0) {
- intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX);
+ intzverg = round_db_to_int_clamp(zverg);
if ( intzverg > *rz || *rz==0x7FFFFFFF) { /* UNIQUE LINE: see comment above */
if (!zspan->rectmask || intzverg > *rm) {
@@ -1260,7 +1260,7 @@ static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr,
x= sn2-sn1;
while (x>=0) {
- intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX);
+ intzverg = round_db_to_int_clamp(zverg);
if (intzverg < *rz) { /* ONLY UNIQUE LINE: see comment above */
if (!zspan->rectmask || intzverg > *rm) {
@@ -1383,7 +1383,7 @@ static void zbuffillGL_onlyZ(ZSpan *zspan, int UNUSED(obi), int UNUSED(zvlnr),
x= sn2-sn1;
while (x>=0) {
- int zvergi= (int)CLAMPIS(zverg, INT_MIN, INT_MAX);
+ int zvergi = round_db_to_int_clamp(zverg);
/* option: maintain two depth values, closest and 2nd closest */
if (zvergi < *rz) {
@@ -1564,20 +1564,13 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
vy0= ((double)my2)*vyd + (double)xx1;
/* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
+ span1= zspan->span1+my2;
+ span2= zspan->span2+my2;
for (i = 0, y = my2; y >= my0; i++, y--, span1--, span2--) {
- sn1= floor(*span1);
- sn2= floor(*span2);
+ sn1= floor(min_ff(*span1, *span2));
+ sn2= floor(max_ff(*span1, *span2));
sn1++;
if (sn2>=rectx) sn2= rectx-1;
@@ -1601,7 +1594,6 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
* Note: uses globals.
* \param v1 start coordinate s
* \param v2 target coordinate t
- * \param b1
* \param b2
* \param b3
* \param a index for coordinate (x, y, or z)
@@ -3494,7 +3486,7 @@ static void add_transp_speed(RenderLayer *rl, int offset, float speed[4], float
RenderPass *rpass;
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (rpass->passtype==SCE_PASS_VECTOR) {
+ if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
float *fp= rpass->rect + 4*offset;
if (speed==NULL) {
@@ -3528,7 +3520,7 @@ static void add_transp_obindex(RenderLayer *rl, int offset, Object *ob)
RenderPass *rpass;
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (rpass->passtype == SCE_PASS_INDEXOB) {
+ if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
float *fp= rpass->rect + offset;
*fp= (float)ob->index;
break;
@@ -3541,7 +3533,7 @@ static void add_transp_material_index(RenderLayer *rl, int offset, Material *mat
RenderPass *rpass;
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (rpass->passtype == SCE_PASS_INDEXMA) {
+ if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
float *fp= rpass->rect + offset;
*fp= (float)mat->index;
break;
@@ -3558,78 +3550,74 @@ static void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
int delta= sizeof(ShadeResult)/4;
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- float *col= NULL;
- int pixsize= 3;
+ float *col = NULL;
+ int pixsize = 3;
- switch (rpass->passtype) {
- case SCE_PASS_RGBA:
- col= shr->col;
- pixsize= 4;
- break;
- case SCE_PASS_EMIT:
- col= shr->emit;
- break;
- case SCE_PASS_DIFFUSE:
- col= shr->diff;
- break;
- case SCE_PASS_SPEC:
- col= shr->spec;
- break;
- case SCE_PASS_SHADOW:
- col= shr->shad;
- break;
- case SCE_PASS_AO:
- col= shr->ao;
- break;
- case SCE_PASS_ENVIRONMENT:
- col= shr->env;
- break;
- case SCE_PASS_INDIRECT:
- col= shr->indirect;
- break;
- case SCE_PASS_REFLECT:
- col= shr->refl;
- break;
- case SCE_PASS_REFRACT:
- col= shr->refr;
- break;
- case SCE_PASS_NORMAL:
- col= shr->nor;
- break;
- case SCE_PASS_MIST:
- col= &shr->mist;
- pixsize= 1;
- break;
- case SCE_PASS_Z:
- col= &shr->z;
- pixsize= 1;
- break;
- case SCE_PASS_VECTOR:
+ if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
+ col = shr->col;
+ pixsize = 4;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
+ col = shr->emit;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
+ col = shr->diff;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
+ col = shr->spec;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
+ col = shr->shad;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
+ col = shr->ao;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
+ col = shr->env;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
+ col = shr->indirect;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
+ col = shr->refl;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
+ col = shr->refr;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
+ col = shr->nor;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
+ col = &shr->mist;
+ pixsize = 1;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
+ col = &shr->z;
+ pixsize = 1;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
+ ShadeResult *shr_t = shr+1;
+ float *fp = shr->winspeed; /* was initialized */
+ int samp;
+
+ /* add minimum speed in pixel */
+ for (samp = 1; samp<R.osa; samp++, shr_t++) {
- {
- ShadeResult *shr_t= shr+1;
- float *fp= shr->winspeed; /* was initialized */
- int samp;
+ if (shr_t->combined[3] > 0.0f) {
+ const float *speed = shr_t->winspeed;
- /* add minimum speed in pixel */
- for (samp= 1; samp<R.osa; samp++, shr_t++) {
-
- if (shr_t->combined[3] > 0.0f) {
- const float *speed= shr_t->winspeed;
-
- if ( (ABS(speed[0]) + ABS(speed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
- fp[0]= speed[0];
- fp[1]= speed[1];
- }
- if ( (ABS(speed[2]) + ABS(speed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
- fp[2]= speed[2];
- fp[3]= speed[3];
- }
- }
+ if ( (ABS(speed[0]) + ABS(speed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
+ fp[0] = speed[0];
+ fp[1] = speed[1];
+ }
+ if ( (ABS(speed[2]) + ABS(speed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
+ fp[2] = speed[2];
+ fp[3] = speed[3];
}
}
- break;
+ }
}
+
if (col) {
const float *fp= col+delta;
int samp;
@@ -3661,53 +3649,51 @@ static void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, flo
float *fp, *col= NULL;
int pixsize= 3;
- switch (rpass->passtype) {
- case SCE_PASS_Z:
- fp= rpass->rect + offset;
- if (shr->z < *fp)
- *fp= shr->z;
- break;
- case SCE_PASS_RGBA:
- fp= rpass->rect + 4*offset;
- addAlphaOverFloat(fp, shr->col);
- break;
- case SCE_PASS_EMIT:
- col= shr->emit;
- break;
- case SCE_PASS_DIFFUSE:
- col= shr->diff;
- break;
- case SCE_PASS_SPEC:
- col= shr->spec;
- break;
- case SCE_PASS_SHADOW:
- col= shr->shad;
- break;
- case SCE_PASS_AO:
- col= shr->ao;
- break;
- case SCE_PASS_ENVIRONMENT:
- col= shr->env;
- break;
- case SCE_PASS_INDIRECT:
- col= shr->indirect;
- break;
- case SCE_PASS_REFLECT:
- col= shr->refl;
- break;
- case SCE_PASS_REFRACT:
- col= shr->refr;
- break;
- case SCE_PASS_NORMAL:
- col= shr->nor;
- break;
- case SCE_PASS_MIST:
- col= &shr->mist;
- pixsize= 1;
- break;
+ if (STREQ(rpass->name, RE_PASSNAME_Z)) {
+ fp = rpass->rect + offset;
+ if (shr->z < *fp)
+ *fp = shr->z;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
+ fp = rpass->rect + 4*offset;
+ addAlphaOverFloat(fp, shr->col);
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
+ col = shr->emit;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
+ col = shr->diff;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
+ col = shr->spec;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
+ col = shr->shad;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
+ col = shr->ao;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
+ col = shr->env;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
+ col = shr->indirect;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
+ col = shr->refl;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
+ col = shr->refr;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
+ col = shr->nor;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
+ col = &shr->mist;
+ pixsize = 1;
}
- if (col) {
+ if (col) {
fp= rpass->rect + pixsize*offset;
fp[0]= col[0] + (1.0f-alpha)*fp[0];
if (pixsize==3) {
@@ -3964,7 +3950,7 @@ static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl, float *rectf
float *fp, *col;
int a;
- fp = RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR, R.viewname);
+ fp = RE_RenderLayerGetPass(rl, RE_PASSNAME_VECTOR, R.viewname);
if (fp==NULL) return;
col= rectf+3;
@@ -4058,7 +4044,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
/* zero alpha pixels get speed vector max again */
if (addpassflag & SCE_PASS_VECTOR)
if (rl->layflag & SCE_LAY_SOLID) {
- float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ float *rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
reset_sky_speedvectors(pa, rl, rl->acolrect ? rl->acolrect : rect); /* if acolrect is set we use it */
}
/* filtered render, for now we assume only 1 filter size */
@@ -4246,7 +4232,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
if (alpha != 0.0f) {
RenderLayer *rl_other = ssamp.rlpp[a];
- float *rect = RE_RenderLayerGetPass(rl_other , SCE_PASS_COMBINED, R.viewname);
+ float *rect = RE_RenderLayerGetPass(rl_other , RE_PASSNAME_COMBINED, R.viewname);
addAlphaOverFloat(rect + 4 * od, samp_shr[a].combined);
add_transp_passes(rl_other , od, &samp_shr[a], alpha);
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index b6245a8c0d1..f22ed34ca2e 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -100,16 +100,6 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
-if(WITH_CODEC_QUICKTIME)
- list(APPEND INC
- ../quicktime
- )
- list(APPEND INC_SYS
- ${QUICKTIME_INCLUDE_DIRS}
- )
- add_definitions(-DWITH_QUICKTIME)
-endif()
-
if(WITH_CODEC_FFMPEG)
list(APPEND INC_SYS
${FFMPEG_INCLUDE_DIRS}
@@ -128,10 +118,6 @@ if(WITH_PYTHON)
../python
)
add_definitions(-DWITH_PYTHON)
-
- if(WITH_PYTHON_SECURITY)
- add_definitions(-DWITH_PYTHON_SECURITY)
- endif()
endif()
if(WITH_GAMEENGINE)
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 2b82f1becb3..7c1c388bcba 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -102,7 +102,8 @@ enum {
};
struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
-struct wmWindow *WM_window_open_temp(struct bContext *C, const struct rcti *rect_init, int type);
+struct wmWindow *WM_window_open_temp(struct bContext *C, int x, int y, int sizex, int sizey, int type);
+void WM_window_set_dpi(wmWindow *win);
/* returns true if draw method is triple buffer */
bool WM_is_draw_triple(struct wmWindow *win);
@@ -186,8 +187,9 @@ struct wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase
/* mouse */
void WM_event_add_mousemove(struct bContext *C);
-bool WM_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
+bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
bool WM_event_is_absolute(const struct wmEvent *event);
+bool WM_event_is_last_mousemove(const struct wmEvent *event);
#ifdef WITH_INPUT_NDOF
/* 3D mouse */
@@ -252,6 +254,7 @@ int WM_operator_confirm_message(struct bContext *C, struct wmOperator *o
/* operator api */
void WM_operator_free (struct wmOperator *op);
+void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op);
void WM_operator_type_set(struct wmOperator *op, struct wmOperatorType *ot);
void WM_operator_stack_clear(struct wmWindowManager *wm);
void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot);
@@ -276,6 +279,7 @@ int WM_operator_call (struct bContext *C, struct wmOperator *op);
int WM_operator_call_notest(struct bContext *C, struct wmOperator *op);
int WM_operator_repeat (struct bContext *C, struct wmOperator *op);
bool WM_operator_repeat_check(const struct bContext *C, struct wmOperator *op);
+bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op);
int WM_operator_name_call_ptr(struct bContext *C, struct wmOperatorType *ot, short context, struct PointerRNA *properties);
int WM_operator_name_call(struct bContext *C, const char *opstring, short context, struct PointerRNA *properties);
int WM_operator_call_py(struct bContext *C, struct wmOperatorType *ot, short context, struct PointerRNA *properties, struct ReportList *reports, const bool is_undo);
@@ -350,6 +354,7 @@ bool WM_operator_pystring_abbreviate(char *str, int str_len_max);
char *WM_prop_pystring_assign(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
void WM_operator_bl_idname(char *to, const char *from);
void WM_operator_py_idname(char *to, const char *from);
+bool WM_operator_py_idname_ok_or_report(struct ReportList *reports, const char *classname, const char *idname);
/* *************** uilist types ******************** */
void WM_uilisttype_init(void);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index cd46e24264d..f6049f10378 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -423,6 +423,7 @@ typedef struct wmGesture {
/* free pointer to use for operator allocs (if set, its freed on exit)*/
void *userdata;
+ bool userdata_free;
} wmGesture;
/* ************** wmEvent ************************ */
@@ -542,7 +543,15 @@ typedef struct wmOperatorType {
* canceled due to some external reason, cancel is called
* - see defines below for return values */
int (*invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
+
+ /* Called when a modal operator is canceled (not used often).
+ * Internal cleanup can be done here if needed. */
void (*cancel)(struct bContext *, struct wmOperator *);
+
+ /* Modal is used for operators which continuously run, eg:
+ * fly mode, knife tool, circle select are all examples of modal operators.
+ * Modal operators can handle events which would normally access other operators,
+ * they keep running until they don't return `OPERATOR_RUNNING_MODAL`. */
int (*modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
/* verify if the operator can be executed in the current context, note
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index b76a1f1d422..a09cc4aeb31 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -107,6 +107,17 @@ void WM_operator_free(wmOperator *op)
MEM_freeN(op);
}
+void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op)
+{
+ op = op->next;
+ while (op != NULL) {
+ wmOperator *op_next = op->next;
+ BLI_remlink(&wm->operators, op);
+ WM_operator_free(op);
+ op = op_next;
+ }
+}
+
/**
* Use with extreme care!,
* properties, customdata etc - must be compatible.
@@ -149,18 +160,23 @@ static void wm_reports_free(wmWindowManager *wm)
void wm_operator_register(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
- int tot;
+ int tot = 0;
BLI_addtail(&wm->operators, op);
- tot = BLI_listbase_count(&wm->operators);
-
- while (tot > MAX_OP_REGISTERED) {
- wmOperator *opt = wm->operators.first;
- BLI_remlink(&wm->operators, opt);
- WM_operator_free(opt);
- tot--;
+
+ /* only count registered operators */
+ while (op) {
+ wmOperator *op_prev = op->prev;
+ if (op->type->flag & OPTYPE_REGISTER) {
+ tot += 1;
+ }
+ if (tot > MAX_OP_REGISTERED) {
+ BLI_remlink(&wm->operators, op);
+ WM_operator_free(op);
+ }
+ op = op_prev;
}
-
+
/* so the console is redrawn */
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
WM_event_add_notifier(C, NC_WM | ND_HISTORY, NULL);
@@ -414,7 +430,7 @@ void wm_clear_default_size(bContext *C)
/* on startup, it adds all data, for matching */
void wm_add_default(bContext *C)
{
- wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan");
+ wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan", 0);
wmWindow *win;
bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */
@@ -467,19 +483,22 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
void wm_close_and_free_all(bContext *C, ListBase *wmlist)
{
- Main *bmain = CTX_data_main(C);
wmWindowManager *wm;
-
+
while ((wm = wmlist->first)) {
wm_close_and_free(C, wm);
BLI_remlink(wmlist, wm);
- BKE_libblock_free_data(bmain, &wm->id);
+ BKE_libblock_free_data(&wm->id, true);
MEM_freeN(wm);
}
}
void WM_main(bContext *C)
{
+ /* Single refresh before handling events.
+ * This ensures we don't run operators before the depsgraph has been evaluated. */
+ wm_event_do_refresh_wm_and_depsgraph(C);
+
while (1) {
/* get events from ghost, handle window events, add to window queues */
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 3a53906a8e8..dd01efdb4c4 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -185,7 +185,7 @@ void WM_drag_free_list(struct ListBase *lb)
}
}
-static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, wmEvent *event)
+static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, const wmEvent *event)
{
wmEventHandler *handler = handlers->first;
for (; handler; handler = handler->next) {
@@ -203,7 +203,7 @@ static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag,
}
/* return active operator name when mouse is in box */
-static const char *wm_dropbox_active(bContext *C, wmDrag *drag, wmEvent *event)
+static const char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = CTX_wm_area(C);
@@ -223,7 +223,7 @@ static const char *wm_dropbox_active(bContext *C, wmDrag *drag, wmEvent *event)
}
-static void wm_drop_operator_options(bContext *C, wmDrag *drag, wmEvent *event)
+static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
const int winsize_x = WM_window_pixels_x(win);
@@ -253,7 +253,7 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, wmEvent *event)
}
/* called in inner handler loop, region context */
-void wm_drags_check_ops(bContext *C, wmEvent *event)
+void wm_drags_check_ops(bContext *C, const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmDrag *drag;
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 3825db14e93..2b695c95258 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -430,7 +430,7 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
return 1;
}
-void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
+void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha, bool is_interlace)
{
const int sizex = WM_window_pixels_x(win);
const int sizey = WM_window_pixels_y(win);
@@ -451,7 +451,13 @@ 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);
+ /* interlace stereo buffer bind the shader before calling wm_triple_draw_textures */
+ if (is_interlace) {
+ glEnable(triple->target);
+ }
+ else {
+ GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT);
+ }
glBindTexture(triple->target, triple->bind);
@@ -472,7 +478,12 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
glBindTexture(triple->target, 0);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ if (is_interlace) {
+ glDisable(triple->target);
+ }
+ else {
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ }
}
static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
@@ -495,7 +506,7 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *tripl
wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true);
glEnable(GL_BLEND);
- wm_triple_draw_textures(win, triple, 1.0f - fac);
+ wm_triple_draw_textures(win, triple, 1.0f - fac, false);
glDisable(GL_BLEND);
}
}
@@ -516,7 +527,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
wmSubWindowSet(win, screen->mainwin);
- wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
}
else {
/* we run it when we start OR when we turn stereo on */
@@ -656,7 +667,7 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi
wmSubWindowSet(win, screen->mainwin);
- wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
}
}
else {
@@ -856,25 +867,13 @@ static bool wm_draw_update_test_window(wmWindow *win)
static int wm_automatic_draw_method(wmWindow *win)
{
- /* Ideally all cards would work well with triple buffer, since if it works
- * well gives the least redraws and is considerably faster at partial redraw
- * for sculpting or drawing overlapping menus. For typically lower end cards
- * copy to texture is slow though and so we use overlap instead there. */
-
+ /* We assume all supported GPUs now support triple buffer well. */
if (win->drawmethod == USER_DRAW_AUTOMATIC) {
- /* Windows software driver darkens color on each redraw */
- if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE))
- return USER_DRAW_OVERLAP_FLIP;
- else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_UNIX, GPU_DRIVER_SOFTWARE))
- return USER_DRAW_OVERLAP;
- /* drawing lower color depth again degrades colors each time */
- else if (GPU_color_depth() < 24)
- return USER_DRAW_OVERLAP;
- else
- return USER_DRAW_TRIPLE;
+ return USER_DRAW_TRIPLE;
}
- else
+ else {
return win->drawmethod;
+ }
}
bool WM_is_draw_triple(wmWindow *win)
@@ -915,15 +914,14 @@ void wm_draw_update(bContext *C)
for (win = wm->windows.first; win; win = win->next) {
#ifdef WIN32
- if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
- GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
-
- if (state == GHOST_kWindowStateMinimized) {
- /* do not update minimized windows, it gives issues on intel drivers (see [#33223])
- * anyway, it seems logical to skip update for invisible windows
- */
- continue;
- }
+ GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
+
+ if (state == GHOST_kWindowStateMinimized) {
+ /* do not update minimized windows, gives issues on Intel (see T33223)
+ * and AMD (see T50856). it seems logical to skip update for invisible
+ * window anyway.
+ */
+ continue;
}
#endif
if (win->drawmethod != U.wmdrawmethod) {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index d2b0acd836b..7e7314cc0c8 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -263,13 +263,56 @@ static void wm_notifier_clear(wmNotifier *note)
memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
}
+/**
+ * Was part of #wm_event_do_notifiers, split out so it can be called once before entering the #WM_main loop.
+ * This ensures operators don't run before the UI and depsgraph are initialized.
+ */
+void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ uint64_t win_combine_v3d_datamask = 0;
+
+ /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
+ }
+
+ /* cached: editor refresh callbacks now, they get context */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ ScrArea *sa;
+
+ CTX_wm_window_set(C, win);
+ for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ if (sa->do_refresh) {
+ CTX_wm_area_set(C, sa);
+ ED_area_do_refresh(C, sa);
+ }
+ }
+
+ /* XXX make lock in future, or separated derivedmesh users in scene */
+ if (G.is_rendering == false) {
+ /* depsgraph & animation: update tagged datablocks */
+ Main *bmain = CTX_data_main(C);
+
+ /* copied to set's in scene_update_tagged_recursive() */
+ win->screen->scene->customdata_mask = win_combine_v3d_datamask;
+
+ /* XXX, hack so operators can enforce datamasks [#26482], gl render */
+ win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
+
+ BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene);
+ }
+ }
+
+ CTX_wm_window_set(C, NULL);
+}
+
/* called in mainloop */
void wm_event_do_notifiers(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmNotifier *note, *next;
wmWindow *win;
- uint64_t win_combine_v3d_datamask = 0;
if (wm == NULL)
return;
@@ -373,39 +416,7 @@ void wm_event_do_notifiers(bContext *C)
MEM_freeN(note);
}
- /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
- for (win = wm->windows.first; win; win = win->next) {
- win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
- }
-
- /* cached: editor refresh callbacks now, they get context */
- for (win = wm->windows.first; win; win = win->next) {
- ScrArea *sa;
-
- CTX_wm_window_set(C, win);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (sa->do_refresh) {
- CTX_wm_area_set(C, sa);
- ED_area_do_refresh(C, sa);
- }
- }
-
- /* XXX make lock in future, or separated derivedmesh users in scene */
- if (G.is_rendering == false) {
- /* depsgraph & animation: update tagged datablocks */
- Main *bmain = CTX_data_main(C);
-
- /* copied to set's in scene_update_tagged_recursive() */
- win->screen->scene->customdata_mask = win_combine_v3d_datamask;
-
- /* XXX, hack so operators can enforce datamasks [#26482], gl render */
- win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
-
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene);
- }
- }
-
- CTX_wm_window_set(C, NULL);
+ wm_event_do_refresh_wm_and_depsgraph(C);
}
static int wm_event_always_pass(const wmEvent *event)
@@ -615,6 +626,16 @@ bool WM_event_is_absolute(const wmEvent *event)
return (event->tablet_data != NULL);
}
+bool WM_event_is_last_mousemove(const wmEvent *event)
+{
+ while ((event = event->next)) {
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ return false;
+ }
+ }
+ return true;
+}
+
#ifdef WITH_INPUT_NDOF
void WM_ndof_deadzone_set(float deadzone)
{
@@ -715,7 +736,9 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
*/
static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot)
{
- return wm && (wm->op_undo_depth == 0) && (ot->flag & OPTYPE_REGISTER);
+ /* Check undo flag here since undo operators are also added to the list,
+ * to support checking if the same operator is run twice. */
+ return wm && (wm->op_undo_depth == 0) && (ot->flag & (OPTYPE_REGISTER | OPTYPE_UNDO));
}
static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat)
@@ -878,6 +901,20 @@ bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
return false;
}
+bool WM_operator_is_repeat(const bContext *C, const wmOperator *op)
+{
+ /* may be in the operators list or not */
+ wmOperator *op_prev;
+ if (op->prev == NULL && op->next == NULL) {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ op_prev = wm->operators.last;
+ }
+ else {
+ op_prev = op->prev;
+ }
+ return (op_prev && (op->type == op_prev->type));
+}
+
static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot,
PointerRNA *properties, ReportList *reports)
{
@@ -1063,6 +1100,9 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
#endif
+/**
+ * Also used for exec when 'event' is NULL.
+ */
static int wm_operator_invoke(
bContext *C, wmOperatorType *ot, wmEvent *event,
PointerRNA *properties, ReportList *reports, const bool poll_only)
@@ -1078,7 +1118,9 @@ static int wm_operator_invoke(
wmOperator *op = wm_operator_create(wm, ot, properties, reports); /* if reports == NULL, they'll be initialized */
const bool is_nested_call = (wm->op_undo_depth != 0);
- op->flag |= OP_IS_INVOKE;
+ if (event != NULL) {
+ op->flag |= OP_IS_INVOKE;
+ }
/* initialize setting from previous run */
if (!is_nested_call) { /* not called by py script */
@@ -2836,7 +2878,7 @@ void WM_event_add_mousemove(bContext *C)
/* for modal callbacks, check configuration for how to interpret exit with tweaks */
-bool WM_modal_tweak_exit(const wmEvent *event, int tweak_event)
+bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
{
/* if the release-confirm userpref setting is enabled,
* tweak events can be canceled when mouse is released
@@ -3179,6 +3221,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
GHOST_TEventCursorData *cd = customdata;
copy_v2_v2_int(&event.x, &cd->x);
+ wm_stereo3d_mouse_offset_apply(win, &event.x);
+
event.type = MOUSEMOVE;
wm_event_add_mousemove(win, &event);
copy_v2_v2_int(&evt->x, &event.x);
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 05d63869074..637ace9cd82 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -316,7 +316,7 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
}
/* in case UserDef was read, we re-initialize all, and do versioning */
-static void wm_init_userdef(bContext *C, const bool from_memory)
+static void wm_init_userdef(bContext *C, const bool read_userdef_from_memory)
{
Main *bmain = CTX_data_main(C);
@@ -336,14 +336,12 @@ static void wm_init_userdef(bContext *C, const bool from_memory)
}
/* avoid re-saving for every small change to our prefs, allow overrides */
- if (from_memory) {
+ if (read_userdef_from_memory) {
BLO_update_defaults_userpref_blend();
}
/* update tempdir from user preferences */
BKE_tempdir_init(U.tempdir);
-
- BKE_blender_userdef_refresh();
}
@@ -451,7 +449,7 @@ void wm_file_read_report(bContext *C)
* Logic shared between #WM_file_read & #wm_homefile_read,
* updates to make after reading a file.
*/
-static void wm_file_read_post(bContext *C, bool is_startup_file)
+static void wm_file_read_post(bContext *C, const bool is_startup_file, const bool use_userdef)
{
bool addons_loaded = false;
wmWindowManager *wm = CTX_wm_manager(C);
@@ -470,9 +468,14 @@ static void wm_file_read_post(bContext *C, bool is_startup_file)
if (is_startup_file) {
/* possible python hasn't been initialized */
if (CTX_py_init_get(C)) {
- /* sync addons, these may have changed from the defaults */
- BPY_execute_string(C, "__import__('addon_utils').reset_all()");
-
+ if (use_userdef) {
+ /* Only run when we have a template path found. */
+ if (BKE_appdir_app_template_any()) {
+ BPY_execute_string(C, "__import__('bl_app_template_utils').reset()");
+ }
+ /* sync addons, these may have changed from the defaults */
+ BPY_execute_string(C, "__import__('addon_utils').reset_all()");
+ }
BPY_python_reset(C);
addons_loaded = true;
}
@@ -554,7 +557,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* confusing this global... */
G.relbase_valid = 1;
- retval = BKE_blendfile_read(C, filepath, reports);
+ retval = BKE_blendfile_read(C, filepath, reports, 0);
/* when loading startup.blend's, we can be left with a blank path */
if (G.main->name[0]) {
G.save_over = 1;
@@ -586,7 +589,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
}
- wm_file_read_post(C, false);
+ wm_file_read_post(C, false, false);
success = true;
}
@@ -629,32 +632,47 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/**
- * called on startup, (context entirely filled with NULLs)
- * or called for 'New File'
- * both startup.blend and userpref.blend are checked
- * the optional parameter custom_file points to an alternative startup page
- * custom_file can be NULL
+ * Called on startup, (context entirely filled with NULLs)
+ * or called for 'New File' both startup.blend and userpref.blend are checked.
+ *
+ * \param use_factory_settings: Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead.
+ * Used for "Restore Factory Settings".
+ * \param use_userdef: Load factory settings as well as startup file.
+ * Disabled for "File New" we don't want to reload preferences.
+ * \param filepath_startup_override: Optional path pointing to an alternative blend file (may be NULL).
+ * \param app_template_override: Template to use instead of the template defined in user-preferences.
+ * When not-null, this is written into the user preferences.
*/
-int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const char *custom_file)
+int wm_homefile_read(
+ bContext *C, ReportList *reports,
+ bool use_factory_settings, bool use_empty_data, bool use_userdef,
+ const char *filepath_startup_override, const char *app_template_override)
{
ListBase wmbase;
- char startstr[FILE_MAX];
- char prefstr[FILE_MAX];
- int success = 0;
+ bool success = false;
+
+ char filepath_startup[FILE_MAX];
+ char filepath_userdef[FILE_MAX];
+
+ /* When 'app_template' is set: '{BLENDER_USER_CONFIG}/{app_template}' */
+ char app_template_system[FILE_MAX];
+ /* When 'app_template' is set: '{BLENDER_SYSTEM_SCRIPTS}/startup/bl_app_templates_system/{app_template}' */
+ char app_template_config[FILE_MAX];
/* Indicates whether user preferences were really load from memory.
*
- * This is used for versioning code, and for this we can not rely on from_memory
+ * This is used for versioning code, and for this we can not rely on use_factory_settings
* passed via argument. This is because there might be configuration folder
* exists but it might not have userpref.blend and in this case we fallback to
* reading home file from memory.
*
* And in this case versioning code is to be run.
*/
- bool read_userdef_from_memory = true;
+ bool read_userdef_from_memory = false;
+ eBLOReadSkip skip_flags = use_userdef ? 0 : BLO_READ_SKIP_USERDEF;
/* options exclude eachother */
- BLI_assert((from_memory && custom_file) == 0);
+ BLI_assert((use_factory_settings && filepath_startup_override) == 0);
if ((G.f & G_SCRIPT_OVERRIDE_PREF) == 0) {
BKE_BIT_TEST_SET(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_SCRIPT_AUTOEXEC);
@@ -665,77 +683,167 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
UI_view2d_zoom_cache_reset();
G.relbase_valid = 0;
- if (!from_memory) {
- const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
- if (custom_file) {
- BLI_strncpy(startstr, custom_file, FILE_MAX);
- if (cfgdir) {
- BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE);
+ /* put aside screens to match with persistent windows later */
+ wm_window_match_init(C, &wmbase);
+
+ filepath_startup[0] = '\0';
+ filepath_userdef[0] = '\0';
+ app_template_system[0] = '\0';
+ app_template_config[0] = '\0';
+
+ const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
+ if (!use_factory_settings) {
+ if (cfgdir) {
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE, NULL);
+ if (use_userdef) {
+ BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL);
}
- else {
- prefstr[0] = '\0';
+ }
+ else {
+ use_factory_settings = true;
+ }
+
+ if (filepath_startup_override) {
+ BLI_strncpy(filepath_startup, filepath_startup_override, FILE_MAX);
+ }
+ }
+
+ /* load preferences before startup.blend */
+ if (use_userdef) {
+ if (!use_factory_settings && BLI_exists(filepath_userdef)) {
+ UserDef *userdef = BKE_blendfile_userdef_read(filepath_userdef, NULL);
+ if (userdef != NULL) {
+ BKE_blender_userdef_set_data(userdef);
+ MEM_freeN(userdef);
+
+ skip_flags |= BLO_READ_SKIP_USERDEF;
+ printf("Read prefs: %s\n", filepath_userdef);
}
}
- else if (cfgdir) {
- BLI_make_file_string(G.main->name, startstr, cfgdir, BLENDER_STARTUP_FILE);
- BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE);
+ }
+
+ const char *app_template = NULL;
+
+ if (filepath_startup_override != NULL) {
+ /* pass */
+ }
+ else if (app_template_override) {
+ /* This may be clearing the current template by setting to an empty string. */
+ app_template = app_template_override;
+ }
+ else if (!use_factory_settings && U.app_template[0]) {
+ app_template = U.app_template;
+ }
+
+ if ((app_template != NULL) && (app_template[0] != '\0')) {
+ BKE_appdir_app_template_id_search(app_template, app_template_system, sizeof(app_template_system));
+
+ /* Insert template name into startup file. */
+
+ /* note that the path is being set even when 'use_factory_settings == true'
+ * this is done so we can load a templates factory-settings */
+ if (!use_factory_settings) {
+ BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL);
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE, NULL);
+ if (BLI_access(filepath_startup, R_OK) != 0) {
+ filepath_startup[0] = '\0';
+ }
}
else {
- startstr[0] = '\0';
- prefstr[0] = '\0';
- from_memory = 1;
+ filepath_startup[0] = '\0';
+ }
+
+ if (filepath_startup[0] == '\0') {
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_system, BLENDER_STARTUP_FILE, NULL);
}
}
-
- /* put aside screens to match with persistent windows later */
- wm_window_match_init(C, &wmbase);
-
- if (!from_memory) {
- if (BLI_access(startstr, R_OK) == 0) {
- success = (BKE_blendfile_read(C, startstr, NULL) != BKE_BLENDFILE_READ_FAIL);
+
+ if (!use_factory_settings || (filepath_startup[0] != '\0')) {
+ if (BLI_access(filepath_startup, R_OK) == 0) {
+ success = (BKE_blendfile_read(C, filepath_startup, NULL, skip_flags) != BKE_BLENDFILE_READ_FAIL);
}
if (BLI_listbase_is_empty(&U.themes)) {
if (G.debug & G_DEBUG)
- printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n", startstr);
- success = 0;
+ printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n", filepath_startup);
+ success = false;
}
}
- if (success == 0 && custom_file && reports) {
- BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", custom_file);
- /*We can not return from here because wm is already reset*/
+ if (success == false && filepath_startup_override && reports) {
+ /* We can not return from here because wm is already reset */
+ BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", filepath_startup_override);
}
- if (success == 0) {
- success = BKE_blendfile_read_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL, true);
+ if (success == false) {
+ success = BKE_blendfile_read_from_memory(
+ C, datatoc_startup_blend, datatoc_startup_blend_size,
+ NULL, skip_flags, true);
+ if (success) {
+ if (use_userdef) {
+ if ((skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
+ read_userdef_from_memory = true;
+ }
+ }
+ }
if (BLI_listbase_is_empty(&wmbase)) {
wm_clear_default_size(C);
}
- BKE_tempdir_init(U.tempdir);
+ }
-#ifdef WITH_PYTHON_SECURITY
- /* use alternative setting for security nuts
- * otherwise we'd need to patch the binary blob - startup.blend.c */
- U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
-#endif
+ if (use_empty_data) {
+ BKE_blendfile_read_make_empty(C);
}
-
- /* check new prefs only after startup.blend was finished */
- if (!from_memory && BLI_exists(prefstr)) {
- int done = BKE_blendfile_read_userdef(prefstr, NULL);
- if (done != BKE_BLENDFILE_READ_FAIL) {
- read_userdef_from_memory = false;
- printf("Read new prefs: %s\n", prefstr);
+
+ /* Load template preferences,
+ * unlike regular preferences we only use some of the settings,
+ * see: BKE_blender_userdef_set_app_template */
+ if (app_template_system[0] != '\0') {
+ char temp_path[FILE_MAX];
+ temp_path[0] = '\0';
+ if (!use_factory_settings) {
+ BLI_path_join(temp_path, sizeof(temp_path), app_template_config, BLENDER_USERPREF_FILE, NULL);
+ if (BLI_access(temp_path, R_OK) != 0) {
+ temp_path[0] = '\0';
+ }
+ }
+
+ if (temp_path[0] == '\0') {
+ BLI_path_join(temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE, NULL);
+ }
+
+ if (use_userdef) {
+ UserDef *userdef_template = NULL;
+ /* just avoids missing file warning */
+ if (BLI_exists(temp_path)) {
+ userdef_template = BKE_blendfile_userdef_read(temp_path, NULL);
+ }
+ if (userdef_template == NULL) {
+ /* we need to have preferences load to overwrite preferences from previous template */
+ userdef_template = BKE_blendfile_userdef_read_from_memory(
+ datatoc_startup_blend, datatoc_startup_blend_size, NULL);
+ read_userdef_from_memory = true;
+ }
+ if (userdef_template) {
+ BKE_blender_userdef_set_app_template(userdef_template);
+ BKE_blender_userdef_free_data(userdef_template);
+ MEM_freeN(userdef_template);
+ }
}
}
-
+
+ if (app_template_override) {
+ BLI_strncpy(U.app_template, app_template_override, sizeof(U.app_template));
+ }
+
/* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise
* can remove this eventually, only in a 2.53 and older, now its not written */
G.fileflags &= ~G_FILE_RELATIVE_REMAP;
- /* check userdef before open window, keymaps etc */
- wm_init_userdef(C, read_userdef_from_memory);
+ if (use_userdef) {
+ /* check userdef before open window, keymaps etc */
+ wm_init_userdef(C, read_userdef_from_memory);
+ }
/* match the read WM with current WM */
wm_window_match_do(C, &wmbase);
@@ -743,14 +851,19 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
G.main->name[0] = '\0';
- /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
- if (!G.background) GPU_default_lights();
-
- /* XXX */
- G.save_over = 0; // start with save preference untitled.blend
- G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in startup.blend... */
+ if (use_userdef) {
+ /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
+ if (!G.background) {
+ GPU_default_lights();
+ }
+ }
+
+ /* start with save preference untitled.blend */
+ G.save_over = 0;
+ /* disable auto-play in startup.blend... */
+ G.fileflags &= ~G_FILE_AUTOPLAY;
- wm_file_read_post(C, true);
+ wm_file_read_post(C, true, use_userdef);
return true;
}
@@ -998,7 +1111,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath);
return ret;
}
-
+
/* note: used to replace the file extension (to ensure '.blend'),
* no need to now because the operator ensures,
* its handy for scripts to save to a predefined name without blender editing it */
@@ -1264,6 +1377,13 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
char filepath[FILE_MAX];
int fileflags;
+ const char *app_template = U.app_template[0] ? U.app_template : NULL;
+ const char * const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template);
+ if (cfgdir == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create user config path");
+ return OPERATOR_CANCELLED;
+ }
+
BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
/* check current window and close it if temp */
@@ -1273,7 +1393,8 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
/* update keymaps in user preferences */
WM_keyconfig_update(wm);
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE, NULL);
+
printf("trying to save homefile at %s ", filepath);
ED_editors_flush_edits(C, false);
@@ -1351,21 +1472,44 @@ static int wm_userpref_write_exec(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
char filepath[FILE_MAX];
+ const char *cfgdir;
+ bool ok = false;
/* update keymaps in user preferences */
WM_keyconfig_update(wm);
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE);
- printf("trying to save userpref at %s ", filepath);
-
- if (BKE_blendfile_write_userdef(filepath, op->reports) == 0) {
- printf("fail\n");
- return OPERATOR_CANCELLED;
+ if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) {
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ printf("trying to save userpref at %s ", filepath);
+ if (BKE_blendfile_userdef_write(filepath, op->reports) != 0) {
+ printf("ok\n");
+ ok = true;
+ }
+ else {
+ printf("fail\n");
+ }
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create userpref path");
}
- printf("ok\n");
+ if (U.app_template[0] && (cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) {
+ /* Also save app-template prefs */
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ printf("trying to save app-template userpref at %s ", filepath);
+ if (BKE_blendfile_userdef_write(filepath, op->reports) == 0) {
+ printf("fail\n");
+ ok = true;
+ }
+ else {
+ printf("ok\n");
+ }
+ }
+ else if (U.app_template[0]) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create app-template userpref path");
+ }
- return OPERATOR_FINISHED;
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void WM_OT_save_userpref(wmOperatorType *ot)
@@ -1400,11 +1544,12 @@ void WM_OT_read_history(wmOperatorType *ot)
static int wm_homefile_read_exec(bContext *C, wmOperator *op)
{
- const bool from_memory = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
+ const bool use_factory_settings = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
+ bool use_userdef = false;
char filepath_buf[FILE_MAX];
const char *filepath = NULL;
- if (!from_memory) {
+ if (!use_factory_settings) {
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
/* This can be used when loading of a start-up file should only change
@@ -1424,9 +1569,36 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
else {
/* always load UI for factory settings (prefs will re-init) */
G.fileflags &= ~G_FILE_NO_UI;
+ /* Always load preferences with factory settings. */
+ use_userdef = true;
+ }
+
+ char app_template_buf[sizeof(U.app_template)];
+ const char *app_template;
+ PropertyRNA *prop_app_template = RNA_struct_find_property(op->ptr, "app_template");
+ const bool use_splash = !use_factory_settings && RNA_boolean_get(op->ptr, "use_splash");
+ const bool use_empty_data = RNA_boolean_get(op->ptr, "use_empty");
+
+ if (prop_app_template && RNA_property_is_set(op->ptr, prop_app_template)) {
+ RNA_property_string_get(op->ptr, prop_app_template, app_template_buf);
+ app_template = app_template_buf;
+
+ /* Always load preferences when switching templates. */
+ use_userdef = true;
+ }
+ else {
+ app_template = NULL;
}
- return wm_homefile_read(C, op->reports, from_memory, filepath) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, use_userdef, filepath, app_template)) {
+ if (use_splash) {
+ WM_init_splash(C);
+ }
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void WM_OT_read_homefile(wmOperatorType *ot)
@@ -1449,17 +1621,36 @@ void WM_OT_read_homefile(wmOperatorType *ot)
"Load user interface setup from the .blend file");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ /* So the splash can be kept open after loading a file (for templates). */
+ prop = RNA_def_boolean(ot->srna, "use_splash", false, "Splash", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
/* omit poll to run in background mode */
}
void WM_OT_read_factory_settings(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
ot->name = "Load Factory Settings";
ot->idname = "WM_OT_read_factory_settings";
ot->description = "Load default file and user preferences";
ot->invoke = WM_operator_confirm;
ot->exec = wm_homefile_read_exec;
+
+ prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
/* omit poll to run in background mode */
}
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 3b733f9558c..7e6c6160b84 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -282,7 +282,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
PropertyRNA *prop;
WMLinkAppendData *lapp_data;
- char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
+ char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX];
char *group, *name;
int totfiles = 0;
short flag;
@@ -608,7 +608,8 @@ static void lib_relocate_do(
}
/* 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);
+ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | ID_REMAP_NO_INDIRECT_PROXY_DATA_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;
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 46203333eb5..cc48b162352 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -71,6 +71,7 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type)
gesture->type = type;
gesture->event_type = event->type;
gesture->swinid = ar->swinid; /* means only in area-region context! */
+ gesture->userdata_free = true; /* Free if userdata is set. */
wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy);
@@ -114,7 +115,7 @@ void WM_gesture_end(bContext *C, wmGesture *gesture)
win->tweak = NULL;
BLI_remlink(&win->gesture, gesture);
MEM_freeN(gesture->customdata);
- if (gesture->userdata) {
+ if (gesture->userdata && gesture->userdata_free) {
MEM_freeN(gesture->userdata);
}
MEM_freeN(gesture);
@@ -137,7 +138,7 @@ int wm_gesture_evaluate(wmGesture *gesture)
int dx = BLI_rcti_size_x(rect);
int dy = BLI_rcti_size_y(rect);
if (abs(dx) + abs(dy) > U.tweak_threshold) {
- int theta = iroundf(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI);
+ int theta = round_fl_to_int(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI);
int val = EVT_GESTURE_W;
if (theta == 0) val = EVT_GESTURE_E;
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index c11c398c616..e73ec2b081a 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -181,18 +181,15 @@ void WM_init(bContext *C, int argc, const char **argv)
ED_file_init(); /* for fsmenu */
ED_node_init_butfuncs();
- BLF_init(11, U.dpi); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
+ BLF_init(); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
BLT_lang_init();
- /* Enforce loading the UI for the initial homefile */
- G.fileflags &= ~G_FILE_NO_UI;
-
/* reports cant be initialized before the wm,
* but keep before file reading, since that may report errors */
wm_init_reports(C);
/* get the default database, plus a wm */
- wm_homefile_read(C, NULL, G.factory_startup, NULL);
+ wm_homefile_read(C, NULL, G.factory_startup, false, true, NULL, NULL);
BLT_lang_set(NULL);
@@ -444,8 +441,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
{
wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;
- BKE_sound_exit();
-
/* first wrap up running stuff, we assume only the active WM is running */
/* modal handlers are on window level freed, others too? */
/* note; same code copied in wm_files.c */
@@ -574,7 +569,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
ED_file_exit(); /* for fsmenu */
UI_exit();
- BKE_blender_userdef_free();
+ BKE_blender_userdef_free_data(&U);
RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */
@@ -591,6 +586,10 @@ void WM_exit_ext(bContext *C, const bool do_python)
BLI_threadapi_exit();
+ /* No need to call this early, rather do it late so that other pieces of Blender using sound may exit cleanly,
+ * see also T50676. */
+ BKE_sound_exit();
+
BKE_blender_atexit();
if (MEM_get_memory_blocks_in_use() != 0) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index e201fa433d4..db5fc23146f 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -121,6 +121,13 @@ static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi)
if (ot->srna != kmi->ptr->type) {
/* matches wm_keymap_item_properties_set but doesnt alloc new ptr */
WM_operator_properties_create_ptr(kmi->ptr, ot);
+ /* 'kmi->ptr->data' NULL'd above, keep using existing properties.
+ * Note: the operators property types may have changed,
+ * we will need a more comprehensive sanitize function to support this properly.
+ */
+ if (kmi->properties) {
+ kmi->ptr->data = kmi->properties;
+ }
WM_operator_properties_sanitize(kmi->ptr, 1);
}
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index b9fd4d2e762..ae5a8319b00 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -177,7 +177,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
/* XXX All ops should have a description but for now allow them not to. */
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
@@ -193,7 +193,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *
ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
opfunc(ot, userdata);
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
@@ -398,7 +398,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
ot->description = UNDOCUMENTED_OPERATOR_TIP;
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
/* Use i18n context from ext.srna if possible (py operators). */
i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLT_I18NCONTEXT_OPERATOR_DEFAULT;
RNA_def_struct_translation_context(ot->srna, i18n_context);
@@ -432,7 +432,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *),
opfunc(ot, userdata);
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
@@ -573,6 +573,46 @@ void WM_operator_bl_idname(char *to, const char *from)
}
/**
+ * Sanity check to ensure #WM_operator_bl_idname won't fail.
+ * \returns true when there are no problems with \a idname, otherwise report an error.
+ */
+bool WM_operator_py_idname_ok_or_report(ReportList *reports, const char *classname, const char *idname)
+{
+ const char *ch = idname;
+ int dot = 0;
+ int i;
+ for (i = 0; *ch; i++, ch++) {
+ if ((*ch >= 'a' && *ch <= 'z') || (*ch >= '0' && *ch <= '9') || *ch == '_') {
+ /* pass */
+ }
+ else if (*ch == '.') {
+ dot++;
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR,
+ "Registering operator class: '%s', invalid bl_idname '%s', at position %d",
+ classname, idname, i);
+ return false;
+ }
+ }
+
+ if (i > (MAX_NAME - 3)) {
+ BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', "
+ "is too long, maximum length is %d", classname, idname,
+ MAX_NAME - 3);
+ return false;
+ }
+
+ if (dot != 1) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character",
+ classname, idname);
+ return false;
+ }
+ return true;
+}
+
+/**
* Print a string representation of the operator, with the args that it runs so python can run it again.
*
* When calling from an existing wmOperator, better to use simple version:
@@ -806,9 +846,19 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
} \
} (void)0
+#define CTX_TEST_SPACE_TYPE(space_data_type, member_full, dataptr_cmp) \
+ { \
+ const char *ctx_member_full = member_full; \
+ if (space_data->spacetype == space_data_type && ptr->data == dataptr_cmp) { \
+ member_id = ctx_member_full; \
+ break; \
+ } \
+ } (void)0
+
switch (GS(((ID *)ptr->id.data)->name)) {
case ID_SCE:
{
+ CTX_TEST_PTR_DATA_TYPE(C, "active_gpencil_brush", RNA_GPencilBrush, ptr, CTX_data_active_gpencil_brush(C));
CTX_TEST_PTR_ID(C, "scene", ptr->id.data);
break;
}
@@ -843,12 +893,22 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
{
CTX_TEST_PTR_ID(C, "screen", ptr->id.data);
- CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, CTX_wm_space_data(C));
+ SpaceLink *space_data = CTX_wm_space_data(C);
+
+ CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, space_data);
CTX_TEST_PTR_DATA_TYPE(C, "area", RNA_Area, ptr, CTX_wm_area(C));
CTX_TEST_PTR_DATA_TYPE(C, "region", RNA_Region, ptr, CTX_wm_region(C));
+ CTX_TEST_SPACE_TYPE(SPACE_IMAGE, "space_data.uv_editor", space_data);
+ CTX_TEST_SPACE_TYPE(SPACE_VIEW3D, "space_data.fx_settings", &(CTX_wm_view3d(C)->fx_settings));
+ CTX_TEST_SPACE_TYPE(SPACE_NLA, "space_data.dopesheet", CTX_wm_space_nla(C)->ads);
+ CTX_TEST_SPACE_TYPE(SPACE_IPO, "space_data.dopesheet", CTX_wm_space_graph(C)->ads);
+ CTX_TEST_SPACE_TYPE(SPACE_ACTION, "space_data.dopesheet", &(CTX_wm_space_action(C)->ads));
+ CTX_TEST_SPACE_TYPE(SPACE_FILE, "space_data.params", CTX_wm_space_file(C)->params);
break;
}
+ default:
+ break;
}
if (member_id) {
@@ -860,6 +920,7 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
}
#undef CTX_TEST_PTR_ID
#undef CTX_TEST_PTR_ID_CAST
+#undef CTX_TEST_SPACE_TYPE
}
return ret;
@@ -900,7 +961,7 @@ void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
{
- wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
if (ot)
WM_operator_properties_create_ptr(ptr, ot);
@@ -1118,6 +1179,7 @@ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op)
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
+ search[0] = '\0';
#if 0 /* ok, this isn't so easy... */
uiDefBut(block, UI_BTYPE_LABEL, 0, RNA_struct_ui_name(op->type->srna), 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
#endif
@@ -1402,20 +1464,6 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
}
}
-static void popup_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
-{
- wmOperator *op = op_ptr;
- if (op->type->check) {
- if (op->type->check(C, op)) {
- /* check for popup and re-layout buttons */
- ARegion *ar_menu = CTX_wm_menu(C);
- if (ar_menu) {
- ED_region_tag_refresh_ui(ar_menu);
- }
- }
- }
-}
-
/* Dialogs are popups that require user verification (click OK) before exec */
static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
{
@@ -1434,8 +1482,6 @@ 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, popup_check_cb, op, NULL);
-
uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
/* clear so the OK button is left alone */
@@ -1474,8 +1520,6 @@ 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);
@@ -1522,7 +1566,7 @@ int WM_operator_ui_popup(bContext *C, wmOperator *op, int width, int height)
data->width = width;
data->height = height;
data->free_op = true; /* if this runs and gets registered we may want not to free it */
- UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data);
+ UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -1552,7 +1596,7 @@ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op,
if (!do_redo || !(U.uiflag & USER_GLOBALUNDO))
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, UI_UNIT_Y);
- UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op);
+ UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op, op);
if (do_call)
wm_block_redo_cb(C, op, 0);
@@ -1594,7 +1638,7 @@ int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int h
data->free_op = true; /* if this runs and gets registered we may want not to free it */
/* op is not executed until popup OK but is clicked */
- UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data);
+ UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -1761,6 +1805,36 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
ibuf = IMB_ibImageFromMemory((unsigned char *)datatoc_splash_png,
datatoc_splash_png_size, IB_rect, NULL, "<splash screen>");
}
+
+ /* overwrite splash with template image */
+ if (U.app_template[0] != '\0') {
+ ImBuf *ibuf_template = NULL;
+ char splash_filepath[FILE_MAX];
+ char template_directory[FILE_MAX];
+
+ if (BKE_appdir_app_template_id_search(
+ U.app_template,
+ template_directory, sizeof(template_directory)))
+ {
+ BLI_join_dirfile(
+ splash_filepath, sizeof(splash_filepath), template_directory,
+ (U.pixelsize == 2) ? "splash_2x.png" : "splash.png");
+ ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL);
+ if (ibuf_template) {
+ const int x_expect = ibuf->x;
+ const int y_expect = 230 * (int)U.pixelsize;
+ /* don't cover the header text */
+ if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) {
+ memcpy(ibuf->rect, ibuf_template->rect, ibuf_template->x * ibuf_template->y * sizeof(char[4]));
+ }
+ else {
+ printf("Splash expected %dx%d found %dx%d, ignoring: %s\n",
+ x_expect, y_expect, ibuf_template->x, ibuf_template->y, splash_filepath);
+ }
+ IMB_freeImBuf(ibuf_template);
+ }
+ }
+ }
#endif
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
@@ -1786,13 +1860,13 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
if (version_suffix != NULL && version_suffix[0]) {
/* placed after the version number in the image,
* placing y is tricky to match baseline */
- int x = 260 - (2 * UI_DPI_WINDOW_FAC);
- int y = 242 + (4 * UI_DPI_WINDOW_FAC);
- int w = 240;
+ int x = 260 * U.pixelsize - (2 * UI_DPI_FAC);
+ int y = 242 * U.pixelsize + (4 * UI_DPI_FAC);
+ int w = 240 * U.pixelsize;
/* hack to have text draw 'text_sel' */
UI_block_emboss_set(block, UI_EMBOSS_NONE);
- but = uiDefBut(block, UI_BTYPE_LABEL, 0, version_suffix, x * U.pixelsize, y * U.pixelsize, w * U.pixelsize, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(block, UI_BTYPE_LABEL, 0, version_suffix, x, y, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
/* XXX, set internal flag - UI_SELECT */
UI_but_flag_enable(but, 1);
UI_block_emboss_set(block, UI_EMBOSS);
@@ -1846,7 +1920,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
BLENDER_VERSION / 100, BLENDER_VERSION % 100);
uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url", url);
uiItemStringO(col, IFACE_("Manual"), ICON_URL, "WM_OT_url_open", "url",
- "http://www.blender.org/manual");
+ "https://docs.blender.org/manual/en/dev/");
uiItemStringO(col, IFACE_("Blender Website"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org");
if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d"
@@ -2521,7 +2595,7 @@ static void tweak_gesture_modal(bContext *C, const wmEvent *event)
}
/* standard tweak, called after window handlers passed on event */
-void wm_tweakevent_test(bContext *C, wmEvent *event, int action)
+void wm_tweakevent_test(bContext *C, const wmEvent *event, int action)
{
wmWindow *win = CTX_wm_window(C);
@@ -3910,8 +3984,12 @@ static void previews_id_ensure(bContext *C, Scene *scene, ID *id)
}
}
-static int previews_id_ensure_callback(void *userdata, ID *UNUSED(self_id), ID **idptr, int UNUSED(cd_flag))
+static int previews_id_ensure_callback(void *userdata, ID *UNUSED(self_id), ID **idptr, int cb_flag)
{
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
PreviewsIDEnsureData *data = userdata;
ID *id = *idptr;
@@ -3944,7 +4022,7 @@ static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op))
preview_id_data.scene = scene;
id = (ID *)scene;
- BKE_library_foreach_ID_link(id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
+ BKE_library_foreach_ID_link(NULL, id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
}
/* Check a last time for ID not used (fake users only, in theory), and
@@ -4558,4 +4636,3 @@ EnumPropertyItem *RNA_mask_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA
{
return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->mask.first : NULL, true);
}
-
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 6bf7bcc2934..77378cf8e0c 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -1256,7 +1256,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
//GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
/* initialize the font */
- BLF_init(11, 72);
+ BLF_init();
ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
BLF_size(ps.fontid, 11, 72);
@@ -1428,8 +1428,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
ps.next_frame = ps.direction;
-
- while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0)) || ps.wait2) {
+ while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, ps.wait2))) {
if (hasevent) {
GHOST_DispatchEvents(g_WS.ghost_system);
}
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 1c1c2ad35af..66ebf18c9e1 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -77,7 +77,7 @@ static void wm_method_draw_stereo3d_pageflip(wmWindow *win)
else //STEREO_RIGHT_ID
glDrawBuffer(GL_BACK_RIGHT);
- wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
}
glDrawBuffer(GL_BACK);
@@ -120,7 +120,7 @@ static void wm_method_draw_stereo3d_interlace(wmWindow *win)
break;
}
- wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f, true);
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
interlace_prev_type = interlace_type;
@@ -157,7 +157,7 @@ static void wm_method_draw_stereo3d_anaglyph(wmWindow *win)
break;
}
- wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
@@ -345,6 +345,32 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
return true;
}
+/**
+ * If needed, this adjusts \a r_mouse_xy so that drawn cursor and handled mouse position are matching visually.
+*/
+void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy)
+{
+ if (!WM_stereo3d_enabled(win, false))
+ return;
+
+ if (win->stereo3d_format->display_mode == S3D_DISPLAY_SIDEBYSIDE) {
+ const int half_x = win->sizex / 2;
+ /* right half of the screen */
+ if (r_mouse_xy[0] > half_x) {
+ r_mouse_xy[0] -= half_x;
+ }
+ r_mouse_xy[0] *= 2;
+ }
+ else if (win->stereo3d_format->display_mode == S3D_DISPLAY_TOPBOTTOM) {
+ const int half_y = win->sizey / 2;
+ /* upper half of the screen */
+ if (r_mouse_xy[1] > half_y) {
+ r_mouse_xy[1] -= half_y;
+ }
+ r_mouse_xy[1] *= 2;
+ }
+}
+
/************************** Stereo 3D operator **********************************/
typedef struct Stereo3dData {
Stereo3dFormat stereo3d_format;
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 2d43c47679d..79078b321da 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -77,6 +77,7 @@
#include "GPU_extensions.h"
#include "GPU_init_exit.h"
#include "GPU_glew.h"
+#include "BLF_api.h"
/* for assert */
#ifndef NDEBUG
@@ -311,7 +312,7 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
if (tmpwin == NULL)
do_exit = 1;
- if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) {
+ if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved && !G.background) {
if (do_exit) {
if (!GHOST_confirmQuit(win->ghostwin))
return;
@@ -374,14 +375,49 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
}
-static float wm_window_get_virtual_pixelsize(void)
+void WM_window_set_dpi(wmWindow *win)
{
- return ((U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1.0f : 2.0f);
-}
+ float auto_dpi = GHOST_GetDPIHint(win->ghostwin);
-float wm_window_pixelsize(wmWindow *win)
-{
- return (GHOST_GetNativePixelSize(win->ghostwin) * wm_window_get_virtual_pixelsize());
+ /* Clamp auto DPI to 96, since our font/interface drawing does not work well
+ * with lower sizes. The main case we are interested in supporting is higher
+ * DPI. If a smaller UI is desired it is still possible to adjust UI scale. */
+ auto_dpi = max_ff(auto_dpi, 96.0f);
+
+ /* Lazily init UI scale size, preserving backwards compatibility by
+ * computing UI scale from ratio of previous DPI and auto DPI */
+ if (U.ui_scale == 0) {
+ int virtual_pixel = (U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1 : 2;
+
+ if (U.dpi == 0) {
+ U.ui_scale = virtual_pixel;
+ }
+ else {
+ U.ui_scale = (virtual_pixel * U.dpi * 96.0f) / (auto_dpi * 72.0f);
+ }
+
+ CLAMP(U.ui_scale, 0.25f, 4.0f);
+ }
+
+ /* Blender's UI drawing assumes DPI 72 as a good default following macOS
+ * while Windows and Linux use DPI 96. GHOST assumes a default 96 so we
+ * remap the DPI to Blender's convention. */
+ auto_dpi *= GHOST_GetNativePixelSize(win->ghostwin);
+ int dpi = auto_dpi * U.ui_scale * (72.0 / 96.0f);
+
+ /* Automatically set larger pixel size for high DPI. */
+ int pixelsize = max_ii(1, (int)(dpi / 64));
+ /* User adjustment for pixel size. */
+ pixelsize = max_ii(1, pixelsize + U.ui_line_width);
+
+ /* Set user preferences globals for drawing, and for forward compatibility. */
+ U.pixelsize = pixelsize;
+ U.dpi = dpi / pixelsize;
+ U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
+ U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72;
+
+ /* update font drawing */
+ BLF_default_dpi(U.pixelsize * U.dpi);
}
/* belongs to below */
@@ -441,8 +477,12 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
/* store actual window size in blender window */
bounds = GHOST_GetClientBounds(win->ghostwin);
- win->sizex = GHOST_GetWidthRectangle(bounds);
- win->sizey = GHOST_GetHeightRectangle(bounds);
+
+ /* win32: gives undefined window size when minimized */
+ if (GHOST_GetWindowState(win->ghostwin) != GHOST_kWindowStateMinimized) {
+ win->sizex = GHOST_GetWidthRectangle(bounds);
+ win->sizey = GHOST_GetHeightRectangle(bounds);
+ }
GHOST_DisposeRectangle(bounds);
#ifndef __APPLE__
@@ -456,10 +496,8 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
glClear(GL_COLOR_BUFFER_BIT);
}
- /* displays with larger native pixels, like Macbook. Used to scale dpi with */
/* needed here, because it's used before it reads userdef */
- U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
+ WM_window_set_dpi(win);
wm_window_swap_buffers(win);
@@ -618,15 +656,27 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
* \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS...
* \return the window or NULL.
*/
-wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
+wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type)
{
wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win;
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
const char *title;
- rcti rect = *rect_init;
- const short px_virtual = (short)wm_window_get_virtual_pixelsize();
+
+ /* convert to native OS window coordinates */
+ const float native_pixel_size = GHOST_GetNativePixelSize(win_prev->ghostwin);
+ x /= native_pixel_size;
+ y /= native_pixel_size;
+ sizex /= native_pixel_size;
+ sizey /= native_pixel_size;
+
+ /* calculate postition */
+ rcti rect;
+ rect.xmin = x + win_prev->posx - sizex / 2;
+ rect.ymin = y + win_prev->posy - sizey / 2;
+ rect.xmax = rect.xmin + sizex;
+ rect.ymax = rect.ymin + sizey;
/* changes rect to fit within desktop */
wm_window_check_position(&rect);
@@ -644,9 +694,8 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
win->posy = rect.ymin;
}
- /* multiply with virtual pixelsize, ghost handles native one (e.g. for retina) */
- win->sizex = BLI_rcti_size_x(&rect) * px_virtual;
- win->sizey = BLI_rcti_size_y(&rect) * px_virtual;
+ win->sizex = BLI_rcti_size_x(&rect);
+ win->sizey = BLI_rcti_size_y(&rect);
if (win->ghostwin) {
wm_window_set_size(win, win->sizex, win->sizey);
@@ -835,8 +884,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
GHOST_ActivateWindowDrawingContext(win->ghostwin);
/* this can change per window */
- U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
+ WM_window_set_dpi(win);
}
}
@@ -1035,6 +1083,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
if (type == GHOST_kEventWindowSize) {
WM_jobs_stop(wm, win->screen, NULL);
}
+
+ WM_window_set_dpi(win);
/* win32: gives undefined window size when minimized */
if (state != GHOST_kWindowStateMinimized) {
@@ -1118,7 +1168,18 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
break;
}
-
+
+ case GHOST_kEventWindowDPIHintChanged:
+ {
+ WM_window_set_dpi(win);
+ /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
+ BLF_cache_clear();
+
+ WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
+ break;
+ }
+
case GHOST_kEventOpenMainFile:
{
PointerRNA props_ptr;
@@ -1199,11 +1260,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
{
// only update if the actual pixel size changes
float prev_pixelsize = U.pixelsize;
- U.pixelsize = wm_window_pixelsize(win);
+ WM_window_set_dpi(win);
if (U.pixelsize != prev_pixelsize) {
- BKE_blender_userdef_refresh();
-
// close all popups since they are positioned with the pixel
// size baked in and it's difficult to correct them
wmWindow *oldWindow = CTX_wm_window(C);
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index 2f06ddab1e8..1206c2b194a 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -57,7 +57,7 @@ void wm_operatortype_free(void);
void wm_operatortype_init(void);
void wm_window_keymap(wmKeyConfig *keyconf);
-void wm_tweakevent_test(bContext *C, wmEvent *event, int action);
+void wm_tweakevent_test(bContext *C, const wmEvent *event, int action);
/* wm_gesture.c */
#define WM_LASSO_MIN_POINTS 1024
@@ -78,6 +78,7 @@ void wm_autosave_location(char *filepath);
/* wm_stereo.c */
void wm_method_draw_stereo3d(const bContext *C, wmWindow *win);
+void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy);
int wm_stereo3d_set_exec(bContext *C, wmOperator *op);
int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *event);
void wm_stereo3d_set_draw(bContext *C, wmOperator *op);
diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h
index 0f125309045..5257bba45ff 100644
--- a/source/blender/windowmanager/wm_draw.h
+++ b/source/blender/windowmanager/wm_draw.h
@@ -56,7 +56,7 @@ void wm_draw_region_clear (struct wmWindow *win, struct ARegion *ar);
void wm_tag_redraw_overlay (struct wmWindow *win, struct ARegion *ar);
-void wm_triple_draw_textures (struct wmWindow *win, struct wmDrawTriple *triple, float alpha);
+void wm_triple_draw_textures (struct wmWindow *win, struct wmDrawTriple *triple, float alpha, bool is_interlace);
void wm_draw_data_free (struct wmWindow *win);
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index efc01b1f8a8..ae04aa5c51b 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -87,13 +87,14 @@ void wm_event_do_handlers (bContext *C);
void wm_event_add_ghostevent (wmWindowManager *wm, wmWindow *win, int type, int time, void *customdata);
-void wm_event_do_notifiers (bContext *C);
+void wm_event_do_refresh_wm_and_depsgraph(bContext *C);
+void wm_event_do_notifiers(bContext *C);
/* wm_keymap.c */
/* wm_dropbox.c */
void wm_dropbox_free(void);
-void wm_drags_check_ops(bContext *C, wmEvent *event);
+void wm_drags_check_ops(bContext *C, const wmEvent *event);
void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect);
#endif /* __WM_EVENT_SYSTEM_H__ */
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 396907a3f6d..b102b6c7cc7 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -35,7 +35,10 @@ struct wmOperatorType;
/* wm_files.c */
void wm_history_file_read(void);
-int wm_homefile_read(struct bContext *C, struct ReportList *reports, bool from_memory, const char *filepath);
+int wm_homefile_read(
+ struct bContext *C, struct ReportList *reports,
+ bool use_factory_settings, bool use_empty_data, bool use_userdef,
+ const char *filepath_startup_override, const char *app_template_override);
void wm_file_read_report(bContext *C);
void WM_OT_save_homefile(struct wmOperatorType *ot);
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index c106f9d7851..f70ec6b47f6 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -63,8 +63,6 @@ void wm_window_swap_buffers (wmWindow *win);
void wm_window_set_swap_interval(wmWindow *win, int interval);
bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
-float wm_window_pixelsize(wmWindow *win);
-
void wm_get_cursor_position (wmWindow *win, int *x, int *y);
void wm_cursor_position_from_ghost (wmWindow *win, int *x, int *y);
void wm_cursor_position_to_ghost (wmWindow *win, int *x, int *y);
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 58bebc66a3e..e5a5ff828dd 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -27,32 +27,17 @@
setup_libdirs()
-if(WITH_CODEC_QUICKTIME)
- add_definitions(-DWITH_QUICKTIME)
-endif()
-
if(WIN32 AND NOT UNIX)
string(SUBSTRING ${BLENDER_VERSION} 0 1 bver1)
string(SUBSTRING ${BLENDER_VERSION} 2 1 bver2)
string(SUBSTRING ${BLENDER_VERSION} 3 1 bver3)
- if(MINGW)
- add_definitions(
- -DWINDRES
- -DBLEN_VER_RC_STR_M=${BLENDER_VERSION}
- -DBLEN_VER_RC_1=${bver1}
- -DBLEN_VER_RC_2=${bver2}
- -DBLEN_VER_RC_3=${bver3}
- -DBLEN_VER_RC_4=0
- )
- else()
- add_definitions(
- -DBLEN_VER_RC_STR=${BLENDER_VERSION}
- -DBLEN_VER_RC_1=${bver1}
- -DBLEN_VER_RC_2=${bver2}
- -DBLEN_VER_RC_3=${bver3}
- -DBLEN_VER_RC_4=0
- )
- endif()
+ add_definitions(
+ -DBLEN_VER_RC_STR=${BLENDER_VERSION}
+ -DBLEN_VER_RC_1=${bver1}
+ -DBLEN_VER_RC_2=${bver2}
+ -DBLEN_VER_RC_3=${bver3}
+ -DBLEN_VER_RC_4=0
+ )
add_executable(
blenderplayer ${EXETYPE}
@@ -176,11 +161,17 @@ endif()
extern_rangetree
extern_wcwidth
bf_intern_libmv
- extern_glog
- extern_gflags
extern_sdlew
)
+ if(NOT WITH_SYSTEM_GLOG)
+ list(APPEND BLENDER_SORTED_LIBS extern_glog)
+ endif()
+
+ if(NOT WITH_SYSTEM_GFLAGS)
+ list(APPEND BLENDER_SORTED_LIBS extern_gflags)
+ endif()
+
if(WITH_MOD_CLOTH_ELTOPO)
list(APPEND BLENDER_SORTED_LIBS extern_eltopo)
endif()
@@ -205,10 +196,6 @@ endif()
list(APPEND BLENDER_SORTED_LIBS extern_xdnd)
endif()
- if(WITH_CODEC_QUICKTIME)
- list(APPEND BLENDER_SORTED_LIBS bf_quicktime)
- endif()
-
if(WITH_CXX_GUARDEDALLOC)
list(APPEND BLENDER_SORTED_LIBS bf_intern_guardedalloc_cpp)
endif()
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 6040dfff644..956f5d5f7ba 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -199,6 +199,7 @@ extern bool pyrna_id_FromPyObject(struct PyObject *obj, struct ID **id);
extern const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid);
extern const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid);
extern struct PyObject *pyrna_id_CreatePyObject(struct ID *id);
+extern bool pyrna_id_CheckPyObject(struct PyObject *obj);
/* bpy_interface.c */
bool BPY_string_is_keyword(const char *str) { return false; }
@@ -229,20 +230,21 @@ void EDBM_mesh_normals_update(struct BMEditMesh *em) RET_NONE
void *g_system;
bool EDBM_mtexpoly_check(struct BMEditMesh *em) RET_ZERO
-float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname) RET_NULL
+float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, const char *name, const char *viewname) RET_NULL
float RE_filter_value(int type, float x) RET_ZERO
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name) RET_NULL
void RE_texture_rng_init() RET_NONE
void RE_texture_rng_exit() RET_NONE
-bool RE_layers_have_name(struct RenderResult *result) {STUB_ASSERT(0); return 0;}
+bool RE_layers_have_name(struct RenderResult *result) RET_ZERO
const char *RE_engine_active_view_get(struct RenderEngine *engine) RET_NULL
-void RE_engine_active_view_set(struct RenderEngine *engine, const char *viewname) {STUB_ASSERT(0);}
-void RE_engine_get_camera_model_matrix(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo, float *r_modelmat) {STUB_ASSERT(0);}
+void RE_engine_active_view_set(struct RenderEngine *engine, const char *viewname) RET_NONE
+void RE_engine_get_camera_model_matrix(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo, float *r_modelmat) RET_NONE
float RE_engine_get_camera_shift_x(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo) RET_ZERO
int RE_engine_get_spherical_stereo(struct RenderEngine *engine, struct Object *camera) RET_ZERO
-void RE_SetActiveRenderView(struct Render *re, const char *viewname) {STUB_ASSERT(0);}
+void RE_SetActiveRenderView(struct Render *re, const char *viewname) RET_NONE
+struct RenderPass *RE_pass_find_by_name(volatile struct RenderLayer *rl, const char *name, const char *viewname) RET_NULL
struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname) RET_NULL
bool RE_HasFakeLayer(RenderResult *res) RET_ZERO
@@ -269,10 +271,13 @@ void RE_sample_material_color(
int tri_index, struct DerivedMesh *orcoDm, struct Object *ob) RET_NONE
/* nodes */
struct Render *RE_GetRender(const char *name) RET_NULL
+struct Render *RE_GetSceneRender(const struct Scene *scene) RET_NULL
struct Object *RE_GetCamera(struct Render *re) RET_NULL
float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]) RET_ZERO
const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4] RET_NULL
const float (*RE_render_current_get_matrix(int matrix_id))[4] RET_NULL
+float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi) RET_ZERO
+float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi) RET_ZERO
/* blenkernel */
bool BKE_paint_proj_mesh_data_check(struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil) RET_ZERO
@@ -286,12 +291,13 @@ void RE_Database_Free(struct Render *re) RET_NONE
void RE_FreeRender(struct Render *re) RET_NONE
void RE_DataBase_GetView(struct Render *re, float mat[4][4]) RET_NONE
int externtex(
- struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta,
+ const struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta,
const int thread, struct ImagePool *pool, const bool skip_load_image, const bool texnode_preview) RET_ZERO
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype) RET_ZERO
void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype) RET_NONE
double elbeemEstimateMemreq(int res, float sx, float sy, float sz, int refine, char *retstr) RET_ZERO
struct Render *RE_NewRender(const char *name) RET_NULL
+struct Render *RE_NewSceneRender(const struct Scene *scene) RET_NULL
void RE_SwapResult(struct Render *re, struct RenderResult **rr) RET_NONE
void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene, struct SceneRenderLayer *srl, struct Object *camera_override, unsigned int lay_override, int frame, const bool write_still) RET_NONE
bool RE_WriteEnvmapResult(struct ReportList *reports, struct Scene *scene, struct EnvMap *env, const char *relpath, const char imtype, float layout[12]) RET_ZERO
@@ -306,6 +312,7 @@ int WM_operator_confirm(struct bContext *C, struct wmOperator *op, const struct
struct MenuType *WM_menutype_find(const char *idname, bool quiet) RET_NULL
void WM_operator_stack_clear(struct wmWindowManager *wm) RET_NONE
void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot) RET_NONE
+bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op) RET_ZERO;
void WM_autosave_init(wmWindowManager *wm) RET_NONE
void WM_jobs_kill_all_except(struct wmWindowManager *wm, void *owner) RET_NONE
@@ -350,7 +357,7 @@ int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struc
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) RET_NONE
void WM_main_add_notifier(unsigned int type, void *reference) RET_NONE
void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep) RET_NONE
-void ED_armature_transform(struct bArmature *arm, float mat[4][4]) RET_NONE
+void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props) RET_NONE
struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op) RET_NULL
struct wmTimer *WM_event_add_timer(struct wmWindowManager *wm, struct wmWindow *win, int event_type, double timestep) RET_NULL
void WM_event_remove_timer(struct wmWindowManager *wm, struct wmWindow *win, struct wmTimer *timer) RET_NONE
@@ -460,24 +467,24 @@ void ED_node_texture_default(const struct bContext *C, struct Tex *tex) RET_NONE
void ED_node_tag_update_id(struct ID *id) RET_NONE
void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node) RET_NONE
void ED_node_tree_update(const struct bContext *C) RET_NONE
-void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo){}
-void ED_init_custom_node_type(struct bNodeType *ntype){}
-void ED_init_custom_node_socket_type(struct bNodeSocketType *stype){}
+void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo) RET_NONE
+void ED_init_custom_node_type(struct bNodeType *ntype) RET_NONE
+void ED_init_custom_node_socket_type(struct bNodeSocketType *stype) RET_NONE
void ED_init_standard_node_socket_type(struct bNodeSocketType *stype) RET_NONE
void ED_init_node_socket_type_virtual(struct bNodeSocketType *stype) RET_NONE
-int ED_node_tree_path_length(struct SpaceNode *snode){return 0;}
-void ED_node_tree_path_get(struct SpaceNode *snode, char *value){}
-void ED_node_tree_path_get_fixedbuf(struct SpaceNode *snode, char *value, int max_length){}
-void ED_node_tree_start(struct SpaceNode *snode, struct bNodeTree *ntree, struct ID *id, struct ID *from){}
-void ED_node_tree_push(struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *gnode){}
-void ED_node_tree_pop(struct SpaceNode *snode){}
+int ED_node_tree_path_length(struct SpaceNode *snode) RET_ZERO
+void ED_node_tree_path_get(struct SpaceNode *snode, char *value) RET_NONE
+void ED_node_tree_path_get_fixedbuf(struct SpaceNode *snode, char *value, int max_length) RET_NONE
+void ED_node_tree_start(struct SpaceNode *snode, struct bNodeTree *ntree, struct ID *id, struct ID *from) RET_NONE
+void ED_node_tree_push(struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *gnode) RET_NONE
+void ED_node_tree_pop(struct SpaceNode *snode) RET_NONE
int ED_view3d_scene_layer_set(int lay, const int *values, int *active) RET_ZERO
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip) RET_NONE
void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist) RET_NONE
struct BGpic *ED_view3D_background_image_new(struct View3D *v3d) RET_NULL
void ED_view3D_background_image_remove(struct View3D *v3d, struct BGpic *bgpic) RET_NONE
void ED_view3D_background_image_clear(struct View3D *v3d) RET_NONE
-void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]) RET_NONE
+void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4], const struct rcti *rect) RET_NONE
float ED_view3d_grid_scale(struct Scene *scene, struct View3D *v3d, const char **grid_unit) RET_ZERO
void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa) RET_NONE
void ED_node_shader_default(const struct bContext *C, struct ID *id) RET_NONE
@@ -548,7 +555,6 @@ SnapObjectContext *ED_transform_snap_object_context_create_view3d(
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) RET_NONE
bool ED_transform_snap_object_project_ray_ex(
struct SnapObjectContext *sctx,
- const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
/* return args */
@@ -649,7 +655,8 @@ struct RenderData *RE_engine_get_render_data(struct Render *re) RET_NULL
void RE_engine_update_result(struct RenderEngine *engine, struct RenderResult *result) RET_NONE
void RE_engine_update_progress(struct RenderEngine *engine, float progress) RET_NONE
void RE_engine_set_error_message(RenderEngine *engine, const char *msg) RET_NONE
-void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int merge_results) RET_NONE
+void RE_engine_add_pass(RenderEngine *engine, const char *name, int channels, const char *chan_id, const char *layername) RET_NONE
+void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int highlight, int merge_results) RET_NONE
void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info) RET_NONE
void RE_layer_load_from_file(struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y) RET_NONE
void RE_result_load_from_file(struct RenderResult *result, struct ReportList *reports, const char *filename) RET_NONE
@@ -668,11 +675,13 @@ struct RenderEngine *RE_engine_create(struct RenderEngineType *type) RET_NULL
void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe) RET_NONE
void RE_FreePersistentData(void) RET_NONE
void RE_point_density_cache(struct Scene *scene, struct PointDensity *pd, const bool use_render_params) RET_NONE
-void RE_point_density_minmax(struct Scene *scene, struct PointDensity *pd, const bool use_render_params, float r_min[3], float r_max[3]) RET_NONE;
-void RE_point_density_sample(struct Scene *scene, struct PointDensity *pd, int resolution, const bool use_render_params, float *values) RET_NONE;
-void RE_point_density_free(struct PointDensity *pd) RET_NONE;
+void RE_point_density_minmax(struct Scene *scene, struct PointDensity *pd, const bool use_render_params, float r_min[3], float r_max[3]) RET_NONE
+void RE_point_density_sample(struct Scene *scene, struct PointDensity *pd, int resolution, const bool use_render_params, float *values) RET_NONE
+void RE_point_density_free(struct PointDensity *pd) RET_NONE
void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) RET_NONE
void RE_FreeAllPersistentData(void) RET_NONE
+float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) RET_ZERO
+void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl, const char *name, int channels, const char *chanid, int type) RET_NONE
/* python */
struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) RET_NULL
@@ -692,6 +701,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(struct wmOperatorType *, void *),
void WM_operatortype_append_macro_ptr(void (*opfunc)(struct wmOperatorType *, void *), void *userdata) RET_NONE
void WM_operator_bl_idname(char *to, const char *from) RET_NONE
void WM_operator_py_idname(char *to, const char *from) RET_NONE
+bool WM_operator_py_idname_ok_or_report(struct ReportList *reports, const char *classname, const char *idname) RET_ZERO
int WM_operator_ui_popup(struct bContext *C, struct wmOperator *op, int width, int height) RET_ZERO
void update_autoflags_fcurve(struct FCurve *fcu, struct bContext *C, struct ReportList *reports, struct PointerRNA *ptr) RET_NONE
short insert_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, char keytype, short flag) RET_ZERO
@@ -713,7 +723,9 @@ struct uiLayout *uiLayoutRadial(struct uiLayout *layout) RET_NULL
int UI_pie_menu_invoke_from_operator_enum(struct bContext *C, const char *title, const char *opname,
const char *propname, const struct wmEvent *event) RET_ZERO
-/* RNA COLLADA dependency */
+/* RNA COLLADA dependency */
+/* XXX (gaia) Why do we need this declaration here? */
+/* The collada header is included anyways further up... */
int collada_export(struct Scene *sce,
const char *filepath,
int apply_modifiers,
@@ -726,8 +738,7 @@ int collada_export(struct Scene *sce,
int deform_bones_only,
int active_uv_only,
- int include_uv_textures,
- int include_material_textures,
+ BC_export_texture_type export_texture_type,
int use_texture_copies,
int triangulate,
@@ -735,12 +746,17 @@ int collada_export(struct Scene *sce,
int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
- int open_sim) RET_ZERO
+ int open_sim,
+ int limit_precision,
+ int keep_bind_info) RET_ZERO
void ED_mesh_calc_tessface(struct Mesh *mesh, bool free_mpoly) RET_NONE
/* bpy/python internal api */
-void operator_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE
+extern void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata);
+extern void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata);
+void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE
+void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE
void BPY_text_free_code(struct Text *text) RET_NONE
void BPY_id_release(struct ID *id) RET_NONE
int BPY_context_member_get(struct bContext *C, const char *member, struct bContextDataResult *result) RET_ZERO
@@ -748,10 +764,10 @@ void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTa
float BPY_driver_exec(PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime) RET_ZERO /* might need this one! */
void BPY_DECREF(void *pyob_ptr) RET_NONE
void BPY_pyconstraint_exec(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets) RET_NONE
-void macro_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE
bool pyrna_id_FromPyObject(struct PyObject *obj, struct ID **id) RET_ZERO
struct PyObject *pyrna_id_CreatePyObject(struct ID *id) RET_NULL
-void BPY_context_update(struct bContext *C) RET_NONE;
+bool pyrna_id_CheckPyObject(struct PyObject *obj) RET_ZERO
+void BPY_context_update(struct bContext *C) RET_NONE
const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid) RET_ARG(msgid)
/* intern/dualcon */
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index aa0a213cf64..54a212f805b 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -113,24 +113,13 @@ if(WIN32 AND NOT UNIX)
string(SUBSTRING ${BLENDER_VERSION} 0 1 bver1)
string(SUBSTRING ${BLENDER_VERSION} 2 1 bver2)
string(SUBSTRING ${BLENDER_VERSION} 3 1 bver3)
- if(MINGW)
- add_definitions(
- -DWINDRES
- -DBLEN_VER_RC_STR_M=${BLENDER_VERSION}
- -DBLEN_VER_RC_1=${bver1}
- -DBLEN_VER_RC_2=${bver2}
- -DBLEN_VER_RC_3=${bver3}
- -DBLEN_VER_RC_4=0
- )
- else()
- add_definitions(
- -DBLEN_VER_RC_STR=${BLENDER_VERSION}
- -DBLEN_VER_RC_1=${bver1}
- -DBLEN_VER_RC_2=${bver2}
- -DBLEN_VER_RC_3=${bver3}
- -DBLEN_VER_RC_4=0
- )
- endif()
+ add_definitions(
+ -DBLEN_VER_RC_STR=${BLENDER_VERSION}
+ -DBLEN_VER_RC_1=${bver1}
+ -DBLEN_VER_RC_2=${bver2}
+ -DBLEN_VER_RC_3=${bver3}
+ -DBLEN_VER_RC_4=0
+ )
list(APPEND SRC
@@ -618,7 +607,7 @@ if(UNIX AND NOT APPLE)
PATTERN "*.pyo" EXCLUDE # * any cache *
)
# On some platforms requests does have extra dependencies.
- set(_requests_deps "chardet" "urllib3")
+ set(_requests_deps "certifi" "chardet" "idna" "urllib3")
foreach(_requests_dep ${_requests_deps})
if(EXISTS ${PYTHON_REQUESTS_PATH}/${_requests_dep})
install(
@@ -652,7 +641,6 @@ elseif(WIN32)
if(WITH_PYTHON)
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
- # MinGW TODO: This bit of Python configuration diverges from MSVC
if(NOT CMAKE_COMPILER_IS_GNUCC)
install(
FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll
@@ -713,10 +701,7 @@ elseif(WIN32)
)
if(WITH_PYTHON_INSTALL_NUMPY)
- set(PYTHON_NUMPY_VERSION 1.9)
- if((MSVC_VERSION EQUAL 1900) OR (MSVC_VERSION EQUAL 1910))
- set(PYTHON_NUMPY_VERSION 1.11)
- endif()
+ set(PYTHON_NUMPY_VERSION 1.13)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
COMMAND ${CMAKE_COMMAND} -E
make_directory ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages)
@@ -724,9 +709,9 @@ elseif(WIN32)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy
COMMAND ${CMAKE_COMMAND} -E
- tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}.tar.gz"
+ tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}$<$<CONFIG:Debug>:d>.tar.gz"
DEPENDS
- ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}.tar.gz
+ ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}$<$<CONFIG:Debug>:d>.tar.gz
${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
)
@@ -752,20 +737,6 @@ elseif(WIN32)
DESTINATION ${BLENDER_VERSION}/python/bin
CONFIGURATIONS Debug
)
-
- # MinGW needs Python DLL
- if(MINGW)
- install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll
- DESTINATION "."
- CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
- )
- install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.dll
- DESTINATION "."
- CONFIGURATIONS Debug
- )
- endif()
endif()
unset(_PYTHON_VERSION_NO_DOTS)
@@ -788,56 +759,19 @@ elseif(WIN32)
FILES ${LIBDIR}/pthreads/lib/pthreadVC2.dll
DESTINATION "."
)
- else()
- #MinGW64 comes with own version. For portable builds it will probaly have to be copied to work
- if(NOT WITH_MINGW64)
- install(
- FILES ${LIBDIR}/pthreads/lib/pthreadGC2.dll
- DESTINATION "."
- )
- elseif(WITH_MINGW64)
- install(
- FILES
- ${LIBDIR}/binaries/libgcc_s_sjlj-1.dll
- ${LIBDIR}/binaries/libwinpthread-1.dll
- ${LIBDIR}/binaries/libstdc++-6.dll
- DESTINATION "."
- )
-
- if(WITH_OPENMP)
- install(
- FILES
- ${LIBDIR}/binaries/libgomp-1.dll
- DESTINATION "."
- )
- endif()
- endif()
endif()
if(WITH_CODEC_FFMPEG)
- if(WITH_MINGW64)
- install(
- FILES
- ${LIBDIR}/ffmpeg/lib/avcodec-53.dll
- ${LIBDIR}/ffmpeg/lib/avformat-53.dll
- ${LIBDIR}/ffmpeg/lib/avdevice-53.dll
- ${LIBDIR}/ffmpeg/lib/avutil-51.dll
- ${LIBDIR}/ffmpeg/lib/swscale-2.dll
- ${LIBDIR}/ffmpeg/lib/swresample-0.dll
- ${LIBDIR}/ffmpeg/lib/xvidcore.dll
- DESTINATION "."
- )
- else()
- install(
- FILES
- ${LIBDIR}/ffmpeg/lib/avcodec-55.dll
- ${LIBDIR}/ffmpeg/lib/avformat-55.dll
- ${LIBDIR}/ffmpeg/lib/avdevice-55.dll
- ${LIBDIR}/ffmpeg/lib/avutil-52.dll
- ${LIBDIR}/ffmpeg/lib/swscale-2.dll
- DESTINATION "."
- )
- endif()
+ install(
+ FILES
+ ${LIBDIR}/ffmpeg/lib/avcodec-57.dll
+ ${LIBDIR}/ffmpeg/lib/avformat-57.dll
+ ${LIBDIR}/ffmpeg/lib/avdevice-57.dll
+ ${LIBDIR}/ffmpeg/lib/avutil-55.dll
+ ${LIBDIR}/ffmpeg/lib/swscale-4.dll
+ ${LIBDIR}/ffmpeg/lib/swresample-2.dll
+ DESTINATION "."
+ )
endif()
if(WITH_CODEC_SNDFILE)
@@ -853,30 +787,13 @@ elseif(WIN32)
${LIBDIR}/openal/lib/OpenAL32.dll
DESTINATION "."
)
- # MinGW TODO: Need to update to a newer OpenAL version
- # which does not depend on wrap_oal.dll
- if(CMAKE_COMPILER_IS_GNUCC)
- install(
- FILES
- ${LIBDIR}/openal/lib/wrap_oal.dll
- DESTINATION "."
- )
- endif()
endif()
if(WITH_SDL)
- #MinGW TODO: Update to SDL2
- if(NOT CMAKE_COMPILER_IS_GNUCC)
- install(
- FILES ${LIBDIR}/sdl/lib/SDL2.dll
- DESTINATION "."
- )
- else()
- install(
- FILES ${LIBDIR}/sdl/lib/SDL.dll
- DESTINATION "."
- )
- endif()
+ install(
+ FILES ${LIBDIR}/sdl/lib/SDL2.dll
+ DESTINATION "."
+ )
endif()
if(WITH_SYSTEM_AUDASPACE)
@@ -903,19 +820,11 @@ elseif(WIN32)
if(WITH_OPENCOLORIO)
set(OCIOBIN ${LIBDIR}/opencolorio/bin)
- if(NOT MINGW)
install(
FILES
${OCIOBIN}/OpenColorIO.dll
DESTINATION "."
)
- else()
- install(
- FILES
- ${OCIOBIN}/libOpenColorIO.dll
- DESTINATION "."
- )
- endif()
endif()
elseif(APPLE)
@@ -936,6 +845,13 @@ elseif(APPLE)
PATTERN "__MACOSX" EXCLUDE
PATTERN ".DS_Store" EXCLUDE
PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib
+ PATTERN "lib2to3" EXCLUDE # ./lib2to3
+ PATTERN "tkinter" EXCLUDE # ./tkinter
+ PATTERN "lib-dynload/_tkinter.*" EXCLUDE # ./lib-dynload/_tkinter.co
+ PATTERN "idlelib" EXCLUDE # ./idlelib
+ PATTERN "test" EXCLUDE # ./test
+ PATTERN "turtledemo" EXCLUDE # ./turtledemo
+ PATTERN "turtle.py" EXCLUDE # ./turtle.py
)
endmacro()
@@ -999,35 +915,10 @@ elseif(APPLE)
# python
if(WITH_PYTHON AND NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK)
- # the python zip is first extract as part of the build process,
- # and then later installed as part of make install. this is much
- # quicker, and means we can easily exclude files on copy
- # Not needed for PYTHON_MODULE or WEB_PLUGIN due uses Pyhon framework
- add_custom_target(
- extractpyzip
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/python)
-
- set(PYTHON_ZIP "python_${CMAKE_OSX_ARCHITECTURES}.zip")
-
- add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/python
- COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/python/"
- COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/python/"
- COMMAND ${CMAKE_COMMAND} -E chdir "${CMAKE_CURRENT_BINARY_DIR}/python/"
- ${CMAKE_COMMAND} -E tar xzfv "${LIBDIR}/release/${PYTHON_ZIP}"
- DEPENDS ${LIBDIR}/release/${PYTHON_ZIP})
-
- add_dependencies(blender extractpyzip)
-
- # copy extracted python files
- install_dir(
- ${CMAKE_CURRENT_BINARY_DIR}/python
- \${TARGETDIR_VER}
- )
- # copy site-packages files
+ # Copy the python libs into the install directory
install_dir(
- ${LIBDIR}/release/site-packages
- ${CMAKE_CURRENT_BINARY_DIR}/python/lib/python${PYTHON_VERSION}
+ ${PYTHON_LIBPATH}
+ ${TARGETDIR_VER}/python/lib
)
install(DIRECTORY ${LIBDIR}/python/bin
@@ -1083,18 +974,10 @@ elseif(APPLE)
# python
if(WITH_PYTHON AND NOT WITH_PYTHON_FRAMEWORK)
- add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/python
- COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/python/"
- COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/python/"
- COMMAND ${CMAKE_COMMAND} -E chdir "${CMAKE_CURRENT_BINARY_DIR}/python/"
- ${CMAKE_COMMAND} -E tar xzfv "${LIBDIR}/release/${PYTHON_ZIP}"
- DEPENDS ${LIBDIR}/release/${PYTHON_ZIP})
-
- # copy extracted python files
+ # Copy the python libs into the install directory
install_dir(
- ${CMAKE_CURRENT_BINARY_DIR}/python
- \${PLAYER_TARGETDIR_VER}
+ ${PYTHON_LIBPATH}
+ ${PLAYER_TARGETDIR_VER}/python/lib
)
endif()
@@ -1185,7 +1068,7 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE)
message(FATAL_ERROR "Windows 10 SDK directory not found")
endif()
endif()
-
+ FILE(TO_CMAKE_PATH ${KITSPATH} KITSPATH)
install(
FILES
${KITSPATH}/api-ms-win-core-file-l1-2-0.dll
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index c3c76a0d1d3..21d03cc8265 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -438,12 +438,12 @@ static void arg_py_context_restore(
* see: `doc/manpage/blender.1.py`
* - Parsed and extracted for the manual,
* which converts our ad-hoc formatting to reStructuredText.
- * see: http://www.blender.org/manual/advanced/command_line.html
+ * see: https://docs.blender.org/manual/en/dev/advanced/command_line.html
*
* \{ */
static const char arg_handle_print_version_doc[] =
-"\n\tPrint Blender version and exit"
+"\n\tPrint Blender version and exit."
;
static int arg_handle_print_version(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -467,10 +467,10 @@ static int arg_handle_print_version(int UNUSED(argc), const char **UNUSED(argv),
}
static const char arg_handle_print_help_doc[] =
-"\n\tPrint this help text and exit"
+"\n\tPrint this help text and exit."
;
static const char arg_handle_print_help_doc_win32[] =
-"\n\tPrint this help text and exit (windows only)"
+"\n\tPrint this help text and exit (windows only)."
;
static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), void *data)
{
@@ -554,6 +554,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
BLI_argsPrintArgDoc(ba, "--debug-gpumem");
BLI_argsPrintArgDoc(ba, "--debug-wm");
BLI_argsPrintArgDoc(ba, "--debug-all");
+ BLI_argsPrintArgDoc(ba, "--debug-io");
printf("\n");
BLI_argsPrintArgDoc(ba, "--debug-fpe");
@@ -585,29 +586,29 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
BLI_argsPrintArgDoc(ba, "--");
printf("\n");
- printf("Other Options:\n");
- BLI_argsPrintOtherDoc(ba);
-
- /* keep last args */
- printf("\n");
printf("Experimental Features:\n");
BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
BLI_argsPrintArgDoc(ba, "--enable-new-basic-shader-glsl");
+ /* Other options _must_ be last (anything not handled will show here) */
+ printf("\n");
+ printf("Other Options:\n");
+ BLI_argsPrintOtherDoc(ba);
+
printf("\n");
printf("Argument Parsing:\n");
printf("\tArguments must be separated by white space, eg:\n");
printf("\t# blender -ba test.blend\n");
- printf("\t...will ignore the 'a'\n");
+ printf("\t...will ignore the 'a'.\n");
printf("\t# blender -b test.blend -f8\n");
- printf("\t...will ignore '8' because there is no space between the '-f' and the frame value\n\n");
+ printf("\t...will ignore '8' because there is no space between the '-f' and the frame value.\n\n");
printf("Argument Order:\n");
printf("\tArguments are executed in the order they are given. eg:\n");
printf("\t# blender --background test.blend --render-frame 1 --render-output '/tmp'\n");
- printf("\t...will not render to '/tmp' because '--render-frame 1' renders before the output path is set\n");
+ printf("\t...will not render to '/tmp' because '--render-frame 1' renders before the output path is set.\n");
printf("\t# blender --background --render-output /tmp test.blend --render-frame 1\n");
- printf("\t...will not render to '/tmp' because loading the blend-file overwrites the render output that was set\n");
+ printf("\t...will not render to '/tmp' because loading the blend-file overwrites the render output that was set.\n");
printf("\t# blender --background test.blend --render-output /tmp --render-frame 1\n");
printf("\t...works as expected.\n\n");
@@ -617,7 +618,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
printf(" $BLENDER_SYSTEM_SCRIPTS Directory for system wide scripts.\n");
printf(" $BLENDER_USER_DATAFILES Directory for user data files (icons, translations, ..).\n");
printf(" $BLENDER_SYSTEM_DATAFILES Directory for system wide data files.\n");
- printf(" $BLENDER_SYSTEM_PYTHON Directory for system python libraries.\n");
+ printf(" $BLENDER_SYSTEM_PYTHON Directory for system Python libraries.\n");
#ifdef WIN32
printf(" $TEMP Store temporary files here.\n");
#else
@@ -626,7 +627,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
#ifdef WITH_SDL
printf(" $SDL_AUDIODRIVER LibSDL audio driver - alsa, esd, dma.\n");
#endif
- printf(" $PYTHONHOME Path to the python directory, eg. /usr/lib/python.\n\n");
+ printf(" $PYTHONHOME Path to the Python directory, eg. /usr/lib/python.\n\n");
exit(0);
@@ -634,7 +635,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
}
static const char arg_handle_arguments_end_doc[] =
-"\n\tEnds option processing, following arguments passed unchanged. Access via Python's 'sys.argv'"
+"\n\tEnd option processing, following arguments passed unchanged. Access via Python's 'sys.argv'."
;
static int arg_handle_arguments_end(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -651,10 +652,10 @@ static int arg_handle_arguments_end(int UNUSED(argc), const char **UNUSED(argv),
#endif
static const char arg_handle_python_set_doc_enable[] =
-"\n\tEnable automatic Python script execution" PY_ENABLE_AUTO
+"\n\tEnable automatic Python script execution" PY_ENABLE_AUTO "."
;
static const char arg_handle_python_set_doc_disable[] =
-"\n\tDisable automatic Python script execution (pydrivers & startup scripts)" PY_DISABLE_AUTO
+"\n\tDisable automatic Python script execution (pydrivers & startup scripts)" PY_DISABLE_AUTO "."
;
#undef PY_ENABLE_AUTO
#undef PY_DISABLE_AUTO
@@ -672,7 +673,7 @@ static int arg_handle_python_set(int UNUSED(argc), const char **UNUSED(argv), vo
}
static const char arg_handle_crash_handler_disable_doc[] =
-"\n\tDisable the crash handler"
+"\n\tDisable the crash handler."
;
static int arg_handle_crash_handler_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -681,7 +682,7 @@ static int arg_handle_crash_handler_disable(int UNUSED(argc), const char **UNUSE
}
static const char arg_handle_abort_handler_disable_doc[] =
-"\n\tDisable the abort handler"
+"\n\tDisable the abort handler."
;
static int arg_handle_abort_handler_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -690,7 +691,7 @@ static int arg_handle_abort_handler_disable(int UNUSED(argc), const char **UNUSE
}
static const char arg_handle_background_mode_set_doc[] =
-"\n\tRun in background (often used for UI-less rendering)"
+"\n\tRun in background (often used for UI-less rendering)."
;
static int arg_handle_background_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -700,7 +701,7 @@ static int arg_handle_background_mode_set(int UNUSED(argc), const char **UNUSED(
static const char arg_handle_debug_mode_set_doc[] =
"\n"
-"\tTurn debugging on\n"
+"\tTurn debugging on.\n"
"\n"
"\t* Enables memory error detection\n"
"\t* Disables mouse grab (to interact with a debugger in some cases)\n"
@@ -725,30 +726,30 @@ static int arg_handle_debug_mode_set(int UNUSED(argc), const char **UNUSED(argv)
#ifdef WITH_FFMPEG
static const char arg_handle_debug_mode_generic_set_doc_ffmpeg[] =
-"\n\tEnable debug messages from FFmpeg library";
+"\n\tEnable debug messages from FFmpeg library.";
#endif
#ifdef WITH_FREESTYLE
static const char arg_handle_debug_mode_generic_set_doc_freestyle[] =
-"\n\tEnable debug messages for FreeStyle";
+"\n\tEnable debug messages for FreeStyle.";
#endif
static const char arg_handle_debug_mode_generic_set_doc_python[] =
-"\n\tEnable debug messages for Python";
+"\n\tEnable debug messages for Python.";
static const char arg_handle_debug_mode_generic_set_doc_events[] =
-"\n\tEnable debug messages for the event system";
+"\n\tEnable debug messages for the event system.";
static const char arg_handle_debug_mode_generic_set_doc_handlers[] =
-"\n\tEnable debug messages for event handling";
+"\n\tEnable debug messages for event handling.";
static const char arg_handle_debug_mode_generic_set_doc_wm[] =
-"\n\tEnable debug messages for the window manager, also prints every operator call";
+"\n\tEnable debug messages for the window manager, also prints every operator call.";
static const char arg_handle_debug_mode_generic_set_doc_jobs[] =
"\n\tEnable time profiling for background jobs.";
static const char arg_handle_debug_mode_generic_set_doc_gpu[] =
"\n\tEnable gpu debug context and information for OpenGL 4.3+.";
static const char arg_handle_debug_mode_generic_set_doc_depsgraph[] =
-"\n\tEnable debug messages from dependency graph";
+"\n\tEnable debug messages from dependency graph.";
static const char arg_handle_debug_mode_generic_set_doc_depsgraph_no_threads[] =
-"\n\tSwitch dependency graph to a single threaded evaluation";
+"\n\tSwitch dependency graph to a single threaded evaluation.";
static const char arg_handle_debug_mode_generic_set_doc_gpumem[] =
-"\n\tEnable GPU memory stats in status bar";
+"\n\tEnable GPU memory stats in status bar.";
static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
{
@@ -756,8 +757,16 @@ static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUS
return 0;
}
+static const char arg_handle_debug_mode_io_doc[] =
+"\n\tEnable debug messages for I/O (collada, ...).";
+static int arg_handle_debug_mode_io(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ G.debug |= G_DEBUG_IO;
+ return 0;
+}
+
static const char arg_handle_debug_mode_all_doc[] =
-"\n\tEnable all debug messages";
+"\n\tEnable all debug messages.";
static int arg_handle_debug_mode_all(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
G.debug |= G_DEBUG_ALL;
@@ -772,7 +781,7 @@ static int arg_handle_debug_mode_all(int UNUSED(argc), const char **UNUSED(argv)
#ifdef WITH_LIBMV
static const char arg_handle_debug_mode_libmv_doc[] =
-"\n\tEnable debug messages from libmv library"
+"\n\tEnable debug messages from libmv library."
;
static int arg_handle_debug_mode_libmv(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -784,7 +793,7 @@ static int arg_handle_debug_mode_libmv(int UNUSED(argc), const char **UNUSED(arg
#ifdef WITH_CYCLES_LOGGING
static const char arg_handle_debug_mode_cycles_doc[] =
-"\n\tEnable debug messages from Cycles"
+"\n\tEnable debug messages from Cycles."
;
static int arg_handle_debug_mode_cycles(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -794,7 +803,7 @@ static int arg_handle_debug_mode_cycles(int UNUSED(argc), const char **UNUSED(ar
#endif
static const char arg_handle_debug_mode_memory_set_doc[] =
-"\n\tEnable fully guarded memory allocation and debugging"
+"\n\tEnable fully guarded memory allocation and debugging."
;
static int arg_handle_debug_mode_memory_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -804,7 +813,7 @@ static int arg_handle_debug_mode_memory_set(int UNUSED(argc), const char **UNUSE
static const char arg_handle_debug_value_set_doc[] =
"<value>\n"
-"\tSet debug value of <value> on startup\n"
+"\tSet debug value of <value> on startup."
;
static int arg_handle_debug_value_set(int argc, const char **argv, void *UNUSED(data))
{
@@ -828,7 +837,7 @@ static int arg_handle_debug_value_set(int argc, const char **argv, void *UNUSED(
}
static const char arg_handle_debug_fpe_set_doc[] =
-"\n\tEnable floating point exceptions"
+"\n\tEnable floating point exceptions."
;
static int arg_handle_debug_fpe_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -837,7 +846,7 @@ static int arg_handle_debug_fpe_set(int UNUSED(argc), const char **UNUSED(argv),
}
static const char arg_handle_factory_startup_set_doc[] =
-"\n\tSkip reading the " STRINGIFY(BLENDER_STARTUP_FILE) " in the users home directory"
+"\n\tSkip reading the " STRINGIFY(BLENDER_STARTUP_FILE) " in the users home directory."
;
static int arg_handle_factory_startup_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -846,11 +855,11 @@ static int arg_handle_factory_startup_set(int UNUSED(argc), const char **UNUSED(
}
static const char arg_handle_env_system_set_doc_datafiles[] =
-"\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_DATAFILES)" environment variable";
+"\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_DATAFILES)" environment variable.";
static const char arg_handle_env_system_set_doc_scripts[] =
-"\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_SCRIPTS)" environment variable";
+"\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_SCRIPTS)" environment variable.";
static const char arg_handle_env_system_set_doc_python[] =
-"\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_PYTHON)" environment variable";
+"\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_PYTHON)" environment variable.";
static int arg_handle_env_system_set(int argc, const char **argv, void *UNUSED(data))
{
@@ -876,13 +885,19 @@ static int arg_handle_env_system_set(int argc, const char **argv, void *UNUSED(d
static const char arg_handle_playback_mode_doc[] =
"<options> <file(s)>\n"
-"\tPlayback <file(s)>, only operates this way when not running in background.\n"
-"\t\t-p <sx> <sy>\tOpen with lower left corner at <sx>, <sy>\n"
-"\t\t-m\t\tRead from disk (Do not buffer)\n"
-"\t\t-f <fps> <fps-base>\t\tSpecify FPS to start with\n"
-"\t\t-j <frame>\tSet frame step to <frame>\n"
-"\t\t-s <frame>\tPlay from <frame>\n"
-"\t\t-e <frame>\tPlay until <frame>"
+"\tPlayback <file(s)>, only operates this way when not running in background.\n\n"
+"\t-p <sx> <sy>\n"
+"\t\tOpen with lower left corner at <sx>, <sy>.\n"
+"\t-m\n"
+"\t\tRead from disk (Do not buffer).\n"
+"\t-f <fps> <fps-base>\n"
+"\t\tSpecify FPS to start with.\n"
+"\t-j <frame>\n"
+"\t\tSet frame step to <frame>.\n"
+"\t-s <frame>\n"
+"\t\tPlay from <frame>.\n"
+"\t-e <frame>\n"
+"\t\tPlay until <frame>."
;
static int arg_handle_playback_mode(int argc, const char **argv, void *UNUSED(data))
{
@@ -902,7 +917,7 @@ static int arg_handle_playback_mode(int argc, const char **argv, void *UNUSED(da
static const char arg_handle_window_geometry_doc[] =
"<sx> <sy> <w> <h>\n"
-"\tOpen with lower left corner at <sx>, <sy> and width and height as <w>, <h>"
+"\tOpen with lower left corner at <sx>, <sy> and width and height as <w>, <h>."
;
static int arg_handle_window_geometry(int argc, const char **argv, void *UNUSED(data))
{
@@ -928,7 +943,7 @@ static int arg_handle_window_geometry(int argc, const char **argv, void *UNUSED(
}
static const char arg_handle_native_pixels_set_doc[] =
-"\n\tDo not use native pixel size, for high resolution displays (MacBook 'Retina')"
+"\n\tDo not use native pixel size, for high resolution displays (MacBook 'Retina')."
;
static int arg_handle_native_pixels_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -937,7 +952,7 @@ static int arg_handle_native_pixels_set(int UNUSED(argc), const char **UNUSED(ar
}
static const char arg_handle_with_borders_doc[] =
-"\n\tForce opening without borders"
+"\n\tForce opening with borders."
;
static int arg_handle_with_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -946,7 +961,7 @@ static int arg_handle_with_borders(int UNUSED(argc), const char **UNUSED(argv),
}
static const char arg_handle_without_borders_doc[] =
-"\n\tForce opening without borders"
+"\n\tForce opening without borders."
;
static int arg_handle_without_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -957,7 +972,7 @@ static int arg_handle_without_borders(int UNUSED(argc), const char **UNUSED(argv
extern bool wm_start_with_console; /* wm_init_exit.c */
static const char arg_handle_start_with_console_doc[] =
-"\n\tStart with the console window open (ignored if -b is set), (Windows only)"
+"\n\tStart with the console window open (ignored if -b is set), (Windows only)."
;
static int arg_handle_start_with_console(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -966,10 +981,10 @@ static int arg_handle_start_with_console(int UNUSED(argc), const char **UNUSED(a
}
static const char arg_handle_register_extension_doc[] =
-"\n\tRegister blend-file extension, then exit (Windows only)"
+"\n\tRegister blend-file extension, then exit (Windows only)."
;
static const char arg_handle_register_extension_doc_silent[] =
-"\n\tSilently register blend-file extension, then exit (Windows only)"
+"\n\tSilently register blend-file extension, then exit (Windows only)."
;
static int arg_handle_register_extension(int UNUSED(argc), const char **UNUSED(argv), void *data)
{
@@ -984,7 +999,7 @@ static int arg_handle_register_extension(int UNUSED(argc), const char **UNUSED(a
}
static const char arg_handle_joystick_disable_doc[] =
-"\n\tDisable joystick support"
+"\n\tDisable joystick support."
;
static int arg_handle_joystick_disable(int UNUSED(argc), const char **UNUSED(argv), void *data)
{
@@ -1005,7 +1020,7 @@ static int arg_handle_joystick_disable(int UNUSED(argc), const char **UNUSED(arg
}
static const char arg_handle_glsl_disable_doc[] =
-"\n\tDisable GLSL shading"
+"\n\tDisable GLSL shading."
;
static int arg_handle_glsl_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -1014,7 +1029,7 @@ static int arg_handle_glsl_disable(int UNUSED(argc), const char **UNUSED(argv),
}
static const char arg_handle_audio_disable_doc[] =
-"\n\tForce sound system to None"
+"\n\tForce sound system to None."
;
static int arg_handle_audio_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -1023,7 +1038,7 @@ static int arg_handle_audio_disable(int UNUSED(argc), const char **UNUSED(argv),
}
static const char arg_handle_audio_set_doc[] =
-"\n\tForce sound system to a specific device\n\tNULL SDL OPENAL JACK"
+"\n\tForce sound system to a specific device.\n\t'NULL' 'SDL' 'OPENAL' 'JACK'."
;
static int arg_handle_audio_set(int argc, const char **argv, void *UNUSED(data))
{
@@ -1073,7 +1088,7 @@ static int arg_handle_output_set(int argc, const char **argv, void *data)
static const char arg_handle_engine_set_doc[] =
"<engine>\n"
-"\tSpecify the render engine\n\tuse -E help to list available engines"
+"\tSpecify the render engine.\n\tUse -E help to list available engines."
;
static int arg_handle_engine_set(int argc, const char **argv, void *data)
{
@@ -1116,11 +1131,11 @@ static int arg_handle_engine_set(int argc, const char **argv, void *data)
static const char arg_handle_image_type_set_doc[] =
"<format>\n"
-"\tSet the render format, Valid options are...\n"
-"\t\tTGA RAWTGA JPEG IRIS IRIZ\n"
-"\t\tAVIRAW AVIJPEG PNG BMP\n"
-"\t(formats that can be compiled into blender, not available on all systems)\n"
-"\t\tHDR TIFF EXR MULTILAYER MPEG FRAMESERVER QUICKTIME CINEON DPX DDS JP2"
+"\tSet the render format.\n"
+"\tValid options are 'TGA' 'RAWTGA' 'JPEG' 'IRIS' 'IRIZ' 'AVIRAW' 'AVIJPEG' 'PNG' 'BMP'\n"
+"\n"
+"\tFormats that can be compiled into Blender, not available on all systems: 'HDR' 'TIFF' 'EXR' 'MULTILAYER'\n"
+"\t'MPEG' 'FRAMESERVER' 'CINEON' 'DPX' 'DDS' 'JP2'"
;
static int arg_handle_image_type_set(int argc, const char **argv, void *data)
{
@@ -1177,7 +1192,7 @@ static int arg_handle_threads_set(int argc, const char **argv, void *UNUSED(data
}
static const char arg_handle_depsgraph_use_new_doc[] =
-"\n\tUse new dependency graph"
+"\n\tUse new dependency graph."
;
static int arg_handle_depsgraph_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -1187,7 +1202,7 @@ static int arg_handle_depsgraph_use_new(int UNUSED(argc), const char **UNUSED(ar
}
static const char arg_handle_basic_shader_glsl_use_new_doc[] =
-"\n\tUse new GLSL basic shader"
+"\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))
{
@@ -1228,7 +1243,7 @@ static int arg_handle_verbosity_set(int argc, const char **argv, void *UNUSED(da
static const char arg_handle_extension_set_doc[] =
"<bool>\n"
-"\tSet option to add the file extension to the end of the file"
+"\tSet option to add the file extension to the end of the file."
;
static int arg_handle_extension_set(int argc, const char **argv, void *data)
{
@@ -1260,10 +1275,15 @@ static int arg_handle_extension_set(int argc, const char **argv, void *data)
static const char arg_handle_ge_parameters_set_doc[] =
"Game Engine specific options\n"
-"\t-g fixedtime\t\tRun on 50 hertz without dropping frames\n"
-"\t-g vertexarrays\t\tUse Vertex Arrays for rendering (usually faster)\n"
-"\t-g nomipmap\t\tNo Texture Mipmapping\n"
-"\t-g linearmipmap\t\tLinear Texture Mipmapping instead of Nearest (default)"
+"\n"
+"\t'fixedtime'\n"
+"\t\tRun on 50 hertz without dropping frames.\n"
+"\t'vertexarrays'\n"
+"\t\tUse Vertex Arrays for rendering (usually faster).\n"
+"\t'nomipmap'\n"
+"\t\tNo Texture Mipmapping.\n"
+"\t'linearmipmap'\n"
+"\t\tLinear Texture Mipmapping instead of Nearest (default)."
;
static int arg_handle_ge_parameters_set(int argc, const char **argv, void *data)
{
@@ -1296,7 +1316,7 @@ static int arg_handle_ge_parameters_set(int argc, const char **argv, void *data)
#endif
}
else {
- printf("error: argument assignment (%s) without value.\n", paramname);
+ printf("Error: argument assignment (%s) without value.\n", paramname);
return 0;
}
/* name arg eaten */
@@ -1353,9 +1373,9 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data)
return 1;
}
- re = RE_NewRender(scene->id.name);
+ re = RE_NewSceneRender(scene);
BLI_begin_threaded_malloc();
- BKE_reports_init(&reports, RPT_PRINT);
+ BKE_reports_init(&reports, RPT_STORE);
RE_SetReports(re, &reports);
for (int i = 0; i < frames_range_len; i++) {
@@ -1370,6 +1390,7 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data)
}
}
RE_SetReports(re, NULL);
+ BKE_reports_clear(&reports);
BLI_end_threaded_malloc();
MEM_freeN(frame_range_arr);
return 1;
@@ -1386,7 +1407,7 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data)
}
static const char arg_handle_render_animation_doc[] =
-"\n\tRender frames from start to end (inclusive)"
+"\n\tRender frames from start to end (inclusive)."
;
static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(argv), void *data)
{
@@ -1394,13 +1415,14 @@ static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(arg
Scene *scene = CTX_data_scene(C);
if (scene) {
Main *bmain = CTX_data_main(C);
- Render *re = RE_NewRender(scene->id.name);
+ Render *re = RE_NewSceneRender(scene);
ReportList reports;
BLI_begin_threaded_malloc();
- BKE_reports_init(&reports, RPT_PRINT);
+ BKE_reports_init(&reports, RPT_STORE);
RE_SetReports(re, &reports);
RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, scene->r.sfra, scene->r.efra, scene->r.frame_step);
RE_SetReports(re, NULL);
+ BKE_reports_clear(&reports);
BLI_end_threaded_malloc();
}
else {
@@ -1411,7 +1433,7 @@ static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(arg
static const char arg_handle_scene_set_doc[] =
"<name>\n"
-"\tSet the active scene <name> for rendering"
+"\tSet the active scene <name> for rendering."
;
static int arg_handle_scene_set(int argc, const char **argv, void *data)
{
@@ -1493,7 +1515,7 @@ static int arg_handle_frame_end_set(int argc, const char **argv, void *data)
static const char arg_handle_frame_skip_set_doc[] =
"<frames>\n"
-"\tSet number of frames to step forward after each rendered frame"
+"\tSet number of frames to step forward after each rendered frame."
;
static int arg_handle_frame_skip_set(int argc, const char **argv, void *data)
{
@@ -1521,7 +1543,7 @@ static int arg_handle_frame_skip_set(int argc, const char **argv, void *data)
static const char arg_handle_python_file_run_doc[] =
"<filename>\n"
-"\tRun the given Python script file"
+"\tRun the given Python script file."
;
static int arg_handle_python_file_run(int argc, const char **argv, void *data)
{
@@ -1549,14 +1571,14 @@ static int arg_handle_python_file_run(int argc, const char **argv, void *data)
}
#else
UNUSED_VARS(argc, argv, data);
- printf("This blender was built without python support\n");
+ printf("This Blender was built without Python support\n");
return 0;
#endif /* WITH_PYTHON */
}
static const char arg_handle_python_text_run_doc[] =
"<name>\n"
-"\tRun the given Python script text block"
+"\tRun the given Python script text block."
;
static int arg_handle_python_text_run(int argc, const char **argv, void *data)
{
@@ -1590,14 +1612,14 @@ static int arg_handle_python_text_run(int argc, const char **argv, void *data)
}
#else
UNUSED_VARS(argc, argv, data);
- printf("This blender was built without python support\n");
+ printf("This Blender was built without Python support\n");
return 0;
#endif /* WITH_PYTHON */
}
static const char arg_handle_python_expr_run_doc[] =
"<expression>\n"
-"\tRun the given expression as a Python script"
+"\tRun the given expression as a Python script."
;
static int arg_handle_python_expr_run(int argc, const char **argv, void *data)
{
@@ -1620,13 +1642,13 @@ static int arg_handle_python_expr_run(int argc, const char **argv, void *data)
}
#else
UNUSED_VARS(argc, argv, data);
- printf("This blender was built without python support\n");
+ printf("This Blender was built without Python support\n");
return 0;
#endif /* WITH_PYTHON */
}
static const char arg_handle_python_console_run_doc[] =
-"\n\tRun blender with an interactive console"
+"\n\tRun Blender with an interactive console."
;
static int arg_handle_python_console_run(int UNUSED(argc), const char **argv, void *data)
{
@@ -1638,7 +1660,7 @@ static int arg_handle_python_console_run(int UNUSED(argc), const char **argv, vo
return 0;
#else
UNUSED_VARS(argv, data);
- printf("This blender was built without python support\n");
+ printf("This Blender was built without python support\n");
return 0;
#endif /* WITH_PYTHON */
}
@@ -1670,7 +1692,7 @@ static int arg_handle_python_exit_code_set(int argc, const char **argv, void *UN
}
static const char arg_handle_addons_set_doc[] =
-"\n\tComma separated list of add-ons (no spaces)"
+"\n\tComma separated list of add-ons (no spaces)."
;
static int arg_handle_addons_set(int argc, const char **argv, void *data)
{
@@ -1805,6 +1827,8 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM);
BLI_argsAdd(ba, 1, NULL, "--debug-all", CB(arg_handle_debug_mode_all), NULL);
+ BLI_argsAdd(ba, 1, NULL, "--debug-io", CB(arg_handle_debug_mode_io), NULL);
+
BLI_argsAdd(ba, 1, NULL, "--debug-fpe",
CB(arg_handle_debug_fpe_set), NULL);
@@ -1875,7 +1899,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
BLI_argsAdd(ba, 4, "-E", "--engine", CB(arg_handle_engine_set), C);
BLI_argsAdd(ba, 4, "-F", "--render-format", CB(arg_handle_image_type_set), C);
- BLI_argsAdd(ba, 4, "-t", "--threads", CB(arg_handle_threads_set), NULL);
+ BLI_argsAdd(ba, 1, "-t", "--threads", CB(arg_handle_threads_set), NULL);
BLI_argsAdd(ba, 4, "-x", "--use-extension", CB(arg_handle_extension_set), C);
#undef CB
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
index d7fe8d8ce59..6e698166fd9 100644
--- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
+++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
@@ -40,7 +40,7 @@
# pragma warning (disable:4786)
#endif
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "KX_BlenderCanvas.h"
#include "KX_BlenderKeyboardDevice.h"
@@ -104,13 +104,13 @@ typedef void * wmUIHandlerRemoveFunc;
# include AUD_DEVICE_H
#endif
-static BlendFileData *load_game_data(char *filename)
+static BlendFileData *load_game_data(const char *filename)
{
ReportList reports;
BlendFileData *bfd;
BKE_reports_init(&reports, RPT_STORE);
- bfd= BLO_read_from_file(filename, &reports);
+ bfd= BLO_read_from_file(filename, &reports, BLO_READ_SKIP_USERDEF);
if (!bfd) {
printf("Loading %s failed: ", filename);
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
index 927b26faf8a..a6b2340d7b4 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
@@ -29,7 +29,7 @@
* \ingroup blroutines
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
diff --git a/source/gameengine/Expressions/intern/HashedPtr.cpp b/source/gameengine/Expressions/intern/HashedPtr.cpp
index 005ac16b231..11d9482f993 100644
--- a/source/gameengine/Expressions/intern/HashedPtr.cpp
+++ b/source/gameengine/Expressions/intern/HashedPtr.cpp
@@ -40,10 +40,8 @@ CHashedPtr::CHashedPtr(void* val) : m_valptr(val)
unsigned int CHashedPtr::hash() const
{
-#if defined(_WIN64) && !defined(FREE_WINDOWS64)
+#if defined(_WIN64)
unsigned __int64 key = (unsigned __int64)m_valptr;
-#elif defined(FREE_WINDOWS64)
- unsigned long long key = (unsigned long long)m_valptr;
#else
unsigned long key = (unsigned long)m_valptr;
#endif
diff --git a/source/gameengine/Expressions/intern/InputParser.cpp b/source/gameengine/Expressions/intern/InputParser.cpp
index e8cc7fba284..583d8da63cb 100644
--- a/source/gameengine/Expressions/intern/InputParser.cpp
+++ b/source/gameengine/Expressions/intern/InputParser.cpp
@@ -37,7 +37,7 @@
// cool things like (IF(LOD==1,CCurvedValue,IF(LOD==2,CCurvedValue2)) etc...
#include "EXP_IfExpr.h"
-#if (defined(WIN32) || defined(WIN64)) && !defined(FREE_WINDOWS)
+#if defined(WIN32) || defined(WIN64)
#define strcasecmp _stricmp
#ifndef strtoll
diff --git a/source/gameengine/Expressions/intern/PyObjectPlus.cpp b/source/gameengine/Expressions/intern/PyObjectPlus.cpp
index de45bee76a7..1e4a59aeb5c 100644
--- a/source/gameengine/Expressions/intern/PyObjectPlus.cpp
+++ b/source/gameengine/Expressions/intern/PyObjectPlus.cpp
@@ -335,7 +335,7 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *
Py_DECREF(resultlist);
return NULL;
}
- // walkthrough
+ ATTR_FALLTHROUGH;
case KX_PYATTRIBUTE_TYPE_INT:
{
int *val = reinterpret_cast<int*>(ptr);
@@ -406,7 +406,7 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *
{
return NULL;
}
- // walkthrough
+ ATTR_FALLTHROUGH;
case KX_PYATTRIBUTE_TYPE_INT:
{
int *val = reinterpret_cast<int*>(ptr);
@@ -638,7 +638,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt
PyErr_Format(PyExc_AttributeError, "Size check error for attribute, \"%s\", report to blender.org", attrdef->m_name);
goto UNDO_AND_ERROR;
}
- // walkthrough
+ ATTR_FALLTHROUGH;
case KX_PYATTRIBUTE_TYPE_INT:
{
int *var = reinterpret_cast<int*>(ptr);
@@ -883,7 +883,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt
PyErr_Format(PyExc_AttributeError, "attribute size check error for attribute \"%s\", report to blender.org", attrdef->m_name);
goto FREE_AND_ERROR;
}
- // walkthrough
+ ATTR_FALLTHROUGH;
case KX_PYATTRIBUTE_TYPE_INT:
{
int *var = reinterpret_cast<int*>(ptr);
diff --git a/source/gameengine/GameLogic/CMakeLists.txt b/source/gameengine/GameLogic/CMakeLists.txt
index 05071f59707..b9eec74f6f4 100644
--- a/source/gameengine/GameLogic/CMakeLists.txt
+++ b/source/gameengine/GameLogic/CMakeLists.txt
@@ -139,6 +139,9 @@ if(WITH_SDL)
if(WITH_GHOST_SDL)
add_definitions(-DWITH_GHOST_SDL)
endif()
+ if(WITH_SDL_DYNLOAD)
+ add_definitions(-DWITH_SDL_DYNLOAD)
+ endif()
endif()
blender_add_lib(ge_logic "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp
index 1a66b2aee52..9f532527a80 100644
--- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp
+++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp
@@ -38,7 +38,11 @@
#include "BLI_path_util.h"
#ifdef WITH_SDL
-# define SDL_CHECK(x) ((x) != (void *)0)
+# ifdef WITH_SDL_DYNLOAD
+# define SDL_CHECK(x) ((x) != (void *)0)
+# else
+# define SDL_CHECK(x) true
+# endif
#endif
SCA_Joystick::SCA_Joystick(short int index)
diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp
index fd3d713b3d2..1dee1de9de2 100644
--- a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp
+++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp
@@ -82,9 +82,11 @@ void SCA_Joystick::HandleEvents(void)
{
SDL_Event sdl_event;
+#ifdef WITH_SDL_DYNLOAD
if (SDL_PollEvent == (void*)0) {
return;
}
+#endif
int i;
for (i=0; i<m_joynum; i++) { /* could use JOYINDEX_MAX but no reason to */
diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
index abb64cf1733..e34a5296139 100644
--- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
@@ -133,7 +133,7 @@ bool SCA_PropertySensor::CheckPropertyCondition()
{
case KX_PROPSENSOR_NOTEQUAL:
reverse = true;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case KX_PROPSENSOR_EQUAL:
{
CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
@@ -231,7 +231,7 @@ bool SCA_PropertySensor::CheckPropertyCondition()
}
case KX_PROPSENSOR_LESSTHAN:
reverse = true;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case KX_PROPSENSOR_GREATERTHAN:
{
CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.h b/source/gameengine/GamePlayer/common/GPC_Canvas.h
index 9a108203ee8..688ed8ac0f4 100644
--- a/source/gameengine/GamePlayer/common/GPC_Canvas.h
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.h
@@ -40,7 +40,7 @@
# include <windows.h>
#endif /* WIN32 */
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <map>
diff --git a/source/gameengine/GamePlayer/common/GPC_MouseDevice.h b/source/gameengine/GamePlayer/common/GPC_MouseDevice.h
index 504df2376bb..24922197723 100644
--- a/source/gameengine/GamePlayer/common/GPC_MouseDevice.h
+++ b/source/gameengine/GamePlayer/common/GPC_MouseDevice.h
@@ -67,8 +67,6 @@ public:
* Call this routine to update the mouse device when a button state changes.
* \param button Which button state changes.
* \param isDown The new state of the button.
- * \param x Position x-coordinate of the cursor at the time of the state change.
- * \param y Position y-coordinate of the cursor at the time of the state change.
* \return Indication as to whether the event was processed.
*/
virtual bool ConvertButtonEvent(TButtonId button, bool isDown);
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
index 408006a0dae..50c34bbadaf 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
@@ -36,7 +36,7 @@
# include <windows.h>
#endif
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "GPU_extensions.h"
#include "GPU_init_exit.h"
diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
index dd93a6ff424..906e9d9a821 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
@@ -355,7 +355,7 @@ static BlendFileData *load_game_data(const char *progname, char *filename = NULL
BLI_strncpy(bfd->main->name, progname, sizeof(bfd->main->name));
}
} else {
- bfd= BLO_read_from_file(progname, &reports);
+ bfd= BLO_read_from_file(progname, &reports, BLO_READ_SKIP_NONE);
}
if (!bfd && filename) {
@@ -516,7 +516,7 @@ int main(
#endif
// Setup builtin font for BLF (mostly copied from creator.c, wm_init_exit.c and interface_style.c)
- BLF_init(11, U.dpi);
+ BLF_init();
BLT_lang_init();
BLT_lang_set("");
diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp
index 95679b5d3a6..9cbd61590b6 100644
--- a/source/gameengine/Ketsji/BL_BlenderShader.cpp
+++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp
@@ -169,7 +169,7 @@ void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty )
rasty->GetViewMatrix().getValue(&viewmat[0][0]);
float auto_bump_scale = ms.m_pDerivedMesh!=0 ? ms.m_pDerivedMesh->auto_bump_scale : 1.0f;
- GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL);
+ GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL, NULL);
mAlphaBlend = GPU_material_alpha_blend(gpumat, obcol);
}
diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp
index 72815cadc70..d344e18c313 100644
--- a/source/gameengine/Ketsji/BL_Shader.cpp
+++ b/source/gameengine/Ketsji/BL_Shader.cpp
@@ -22,7 +22,7 @@
* \ingroup ketsji
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <iostream>
#include "BL_Shader.h"
diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp
index cc7fea5ad25..c3b799b9424 100644
--- a/source/gameengine/Ketsji/BL_Texture.cpp
+++ b/source/gameengine/Ketsji/BL_Texture.cpp
@@ -22,7 +22,7 @@
* \ingroup ketsji
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <iostream>
#include <map>
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
index 476fbd29b8b..d26e35f8138 100644
--- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
@@ -22,7 +22,7 @@
* \ingroup ketsji
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "KX_BlenderMaterial.h"
#include "BL_Material.h"
diff --git a/source/gameengine/Ketsji/KX_Dome.h b/source/gameengine/Ketsji/KX_Dome.h
index 420565e62f6..5a0c4588ae2 100644
--- a/source/gameengine/Ketsji/KX_Dome.h
+++ b/source/gameengine/Ketsji/KX_Dome.h
@@ -38,7 +38,7 @@
#include "RAS_IRasterizer.h"
#include "KX_KetsjiEngine.h"
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <vector>
#include "MEM_guardedalloc.h"
diff --git a/source/gameengine/Ketsji/KX_FontObject.cpp b/source/gameengine/Ketsji/KX_FontObject.cpp
index 364f8d4bfc6..91e8e4fd42b 100644
--- a/source/gameengine/Ketsji/KX_FontObject.cpp
+++ b/source/gameengine/Ketsji/KX_FontObject.cpp
@@ -281,7 +281,7 @@ int KX_FontObject::pyattr_set_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrd
KX_FontObject* self = static_cast<KX_FontObject*>(self_v);
if (!PyUnicode_Check(value))
return PY_SET_ATTR_FAIL;
- char* chars = _PyUnicode_AsString(value);
+ const char *chars = _PyUnicode_AsString(value);
/* Allow for some logic brick control */
CValue* tprop = self->GetProperty("Text");
diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.cpp b/source/gameengine/Ketsji/KX_IPO_SGController.cpp
index f3947fdd710..be1a4b4ef3a 100644
--- a/source/gameengine/Ketsji/KX_IPO_SGController.cpp
+++ b/source/gameengine/Ketsji/KX_IPO_SGController.cpp
@@ -31,10 +31,8 @@
*/
-#if defined(_WIN64) && !defined(FREE_WINDOWS64)
+#if defined(_WIN64)
typedef unsigned __int64 uint_ptr;
-#elif defined(FREE_WINDOWS64)
-typedef unsigned long long uint_ptr;
#else
typedef unsigned long uint_ptr;
#endif
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index b0a8e376eb6..d82a0fd533b 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -80,12 +80,6 @@
#define DEFAULT_LOGIC_TIC_RATE 60.0
//#define DEFAULT_PHYSICS_TIC_RATE 60.0
-#ifdef FREE_WINDOWS /* XXX mingw64 (gcc 4.7.0) defines a macro for DrawText that translates to DrawTextA. Not good */
-#ifdef DrawText
-#undef DrawText
-#endif
-#endif
-
const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = {
"Physics:", // tc_physics
"Logic:", // tc_logic
diff --git a/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp b/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp
index 239bfde4c98..c84b2474c90 100644
--- a/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp
+++ b/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp
@@ -345,6 +345,7 @@ static MT_Point3 nearestPointToObstacle(MT_Point3& pos ,KX_Obstacle* obstacle)
MT_Point3 res = obstacle->m_pos + abdir*proj;
return res;
}
+ ATTR_FALLTHROUGH;
}
case KX_OBSTACLE_CIRCLE :
default:
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index cdc2f9f3644..5540aad7a3f 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -30,7 +30,7 @@
* \ingroup ketsji
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#ifdef _MSC_VER
# pragma warning (disable:4786)
@@ -40,11 +40,6 @@
# ifdef _XOPEN_SOURCE
# undef _XOPEN_SOURCE
# endif
-# if defined(__sun) || defined(sun)
-# if defined(_XPG4)
-# undef _XPG4
-# endif
-# endif
# include <Python.h>
extern "C" {
diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp
index a27f37c0441..d858097abef 100644
--- a/source/gameengine/Ketsji/KX_SoundActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp
@@ -108,7 +108,7 @@ void KX_SoundActuator::play()
case KX_SOUNDACT_LOOPBIDIRECTIONAL:
case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP:
sound = AUD_Sound_pingpong(sound);
- // fall through
+ ATTR_FALLTHROUGH;
case KX_SOUNDACT_LOOPEND:
case KX_SOUNDACT_LOOPSTOP:
loop = true;
@@ -124,7 +124,7 @@ void KX_SoundActuator::play()
AUD_Device_free(device);
// in case of pingpong, we have to free the sound
- if(sound != m_sound)
+ if (sound != m_sound)
AUD_Sound_free(sound);
if (m_handle != NULL) {
diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt
index e52dc1ba052..8b00f1b47fa 100644
--- a/source/gameengine/Physics/Bullet/CMakeLists.txt
+++ b/source/gameengine/Physics/Bullet/CMakeLists.txt
@@ -37,6 +37,7 @@ set(INC
../../SceneGraph
../../../blender/blenkernel
../../../blender/blenlib
+ ../../../blender/gpu
../../../blender/makesdna
../../../../intern/container
../../../../intern/guardedalloc
diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt
index c65fcac5161..fc7dc90e03b 100644
--- a/source/gameengine/Rasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../../blender/makesdna
../../blender/blenlib
../../blender/blenkernel
+ ../../blender/gpu
../../blender/imbuf
../../../intern/container
../../../intern/glew-mx
diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
index 82b26749fd1..f379e2eb486 100644
--- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
+++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
@@ -24,7 +24,7 @@
* \ingroup bgerast
*/
-#define STRINGIFY(A) #A
+#include "BLI_utildefines.h"
#include "RAS_OpenGLFilters/RAS_Blur2DFilter.h"
#include "RAS_OpenGLFilters/RAS_Sharpen2DFilter.h"
@@ -43,7 +43,7 @@
#include "RAS_2DFilterManager.h"
#include <iostream>
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <stdio.h>
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
index b2d580161ca..71c8cfe745f 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
@@ -30,7 +30,7 @@
#include <windows.h>
#endif // WIN32
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "RAS_MaterialBucket.h"
#include "RAS_TexVert.h"
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
index fff988a07c5..69e859f06d9 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <stdio.h>
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
index e589bffcaf1..58b3c61bd05 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <stdio.h>
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
index 3f82c513f7d..5eed9b3b8f8 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
@@ -35,7 +35,7 @@
#include "RAS_OpenGLRasterizer.h"
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "RAS_ICanvas.h"
#include "RAS_Rect.h"
@@ -994,8 +994,8 @@ 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);
+ bool negY = (scale[1] < 0.0f);
+ bool negZ = (scale[2] < 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);
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
index d54b3232067..26b956cd74e 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <stdio.h>
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
index 316871e6025..f980116f5f8 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
@@ -27,7 +27,7 @@
#include "RAS_StorageVA.h"
-#include "glew-mx.h"
+#include "GPU_glew.h"
RAS_StorageVA::RAS_StorageVA(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer) :
m_drawingmode(RAS_IRasterizer::KX_TEXTURED),
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
index 114defb60a5..4ba5882a46e 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
@@ -28,7 +28,7 @@
#include "RAS_StorageVBO.h"
#include "RAS_MeshObject.h"
-#include "glew-mx.h"
+#include "GPU_glew.h"
VBO::VBO(RAS_DisplayArray *data, unsigned int indices)
{
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
index 4c8e4a8931c..c82b6a3206d 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
@@ -29,7 +29,7 @@
#define __KX_VERTEXBUFFEROBJECTSTORAGE
#include <map>
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "RAS_IStorage.h"
#include "RAS_IRasterizer.h"
diff --git a/source/gameengine/VideoTexture/FilterBase.cpp b/source/gameengine/VideoTexture/FilterBase.cpp
index 5717a1edbcb..b41a2095890 100644
--- a/source/gameengine/VideoTexture/FilterBase.cpp
+++ b/source/gameengine/VideoTexture/FilterBase.cpp
@@ -114,6 +114,7 @@ void Filter_dealloc(PyFilter *self)
delete self->m_filter;
self->m_filter = NULL;
}
+ Py_TYPE((PyObject *)self)->tp_free((PyObject *)self);
}
diff --git a/source/gameengine/VideoTexture/FilterColor.cpp b/source/gameengine/VideoTexture/FilterColor.cpp
index eed84a8580c..15a7e9e4cd1 100644
--- a/source/gameengine/VideoTexture/FilterColor.cpp
+++ b/source/gameengine/VideoTexture/FilterColor.cpp
@@ -68,7 +68,7 @@ PyTypeObject FilterGrayType =
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
- "Filter for gray scale effect", /* tp_doc */
+ "Filter for grayscale effect", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
diff --git a/source/gameengine/VideoTexture/FilterColor.h b/source/gameengine/VideoTexture/FilterColor.h
index 350f7270874..d042863d7e8 100644
--- a/source/gameengine/VideoTexture/FilterColor.h
+++ b/source/gameengine/VideoTexture/FilterColor.h
@@ -36,7 +36,7 @@
#include "FilterBase.h"
-/// pixel filter for gray scale
+/// pixel filter for grayscale
class FilterGray : public FilterBase
{
public:
@@ -53,7 +53,7 @@ protected:
// calculate gray value
unsigned int gray = (28 * (VT_B(val)) + 151 * (VT_G(val))
+ 77 * (VT_R(val))) >> 8;
- // return gray scale value
+ // return grayscale value
VT_R(val) = gray;
VT_G(val) = gray;
VT_B(val) = gray;
diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp
index 0db1fa293da..a547d2a7a85 100644
--- a/source/gameengine/VideoTexture/ImageBase.cpp
+++ b/source/gameengine/VideoTexture/ImageBase.cpp
@@ -43,7 +43,7 @@ extern "C" {
#include "Exception.h"
-#if (defined(WIN32) || defined(WIN64)) && !defined(FREE_WINDOWS)
+#if (defined(WIN32) || defined(WIN64))
#define strcasecmp _stricmp
#endif
@@ -427,6 +427,7 @@ void Image_dealloc(PyImage *self)
delete self->m_image;
self->m_image = NULL;
}
+ Py_TYPE((PyObject *)self)->tp_free((PyObject *)self);
}
// get image data
diff --git a/source/gameengine/VideoTexture/ImageBase.h b/source/gameengine/VideoTexture/ImageBase.h
index 4c9fc5a58fb..5a09c9a67b3 100644
--- a/source/gameengine/VideoTexture/ImageBase.h
+++ b/source/gameengine/VideoTexture/ImageBase.h
@@ -40,7 +40,7 @@
#include "FilterBase.h"
-#include "glew-mx.h"
+#include "GPU_glew.h"
// forward declarations
struct PyImage;
diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp
index 9991bf42a9f..57062343b67 100644
--- a/source/gameengine/VideoTexture/ImageRender.cpp
+++ b/source/gameengine/VideoTexture/ImageRender.cpp
@@ -36,7 +36,7 @@
#include <math.h>
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "KX_PythonInit.h"
#include "DNA_scene_types.h"
@@ -734,6 +734,7 @@ ImageRender::ImageRender (KX_Scene *scene, KX_GameObject *observer, KX_GameObjec
m_done(false),
m_scene(scene),
m_offscreen(NULL),
+ m_sync(NULL),
m_observer(observer),
m_mirror(mirror),
m_clip(100.f)
diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp
index 8852c190053..ad3d8875e28 100644
--- a/source/gameengine/VideoTexture/ImageViewport.cpp
+++ b/source/gameengine/VideoTexture/ImageViewport.cpp
@@ -33,7 +33,7 @@
#include "EXP_PyObjectPlus.h"
#include <structmember.h>
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "KX_PythonInit.h"
#include "RAS_ICanvas.h"
diff --git a/source/gameengine/VideoTexture/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp
index bb995747360..48dc4c705bf 100644
--- a/source/gameengine/VideoTexture/Texture.cpp
+++ b/source/gameengine/VideoTexture/Texture.cpp
@@ -55,7 +55,7 @@
#include "Exception.h"
#include <memory.h>
-#include "glew-mx.h"
+#include "GPU_glew.h"
extern "C" {
#include "IMB_imbuf.h"
diff --git a/source/gameengine/VideoTexture/VideoDeckLink.h b/source/gameengine/VideoTexture/VideoDeckLink.h
index 50099d2ead4..d5419176691 100644
--- a/source/gameengine/VideoTexture/VideoDeckLink.h
+++ b/source/gameengine/VideoTexture/VideoDeckLink.h
@@ -47,7 +47,7 @@ extern "C" {
#include "BLI_threads.h"
#include "BLI_blenlib.h"
}
-#include "GL/glew.h"
+#include "GPU_glew.h"
#ifdef WIN32
#include "dvpapi.h"
#endif
diff --git a/source/tools b/source/tools
-Subproject 896c5f78952adb2d091d28c65086d46992dabda
+Subproject b11375e89061303401376f7aeae42ac2fd64692